TCP 协议深度剖析:三次握手、四次挥手及 TIME_WAIT 优化

发布于 2026-06-02 · 分类:网络原理 · 阅读约 14 分钟
首页 / 网络原理 / 正文

TCP(Transmission Control Protocol,传输控制协议)是面向连接的、可靠的、基于字节流的全双工传输层通信协议。无论是 HTTP/1.1、HTTP/2,还是基于 TLS 的安全信道,其最底层都是构建在 TCP 稳定传输的基础之上的。

1. 为什么必须是“三次握手”?

本质原因:为了防止已失效的连接请求报文段突然又传送到了服务端,因而产生错误。 同时,三次握手是客户端和服务端双方确认彼此具有“发送能力”和“接收能力”的最小法定次数:

  1. 第一次握手 (SYN=1, seq=x): 服务端确认了“客户端发送能力正常,服务端接收能力正常”。
  2. 第二次握手 (SYN=1, ACK=1, seq=y, ack=x+1): 客户端确认了“服务端发送与接收均正常,客户端自己的发送与接收也正常”。
  3. 第三次握手 (ACK=1, seq=x+1, ack=y+1): 服务端确认了“客户端接收能力正常”。

至此,双方初始序列号(ISN)成功同步,TCP 状态转入 ESTABLISHED。

2. 为什么关闭连接需要“四次挥手”?

TCP 是全双工通信(双向数据流动独立)。当一方发送 FIN 报文时,仅表示该端已经没有数据需要向对方发送了;但对方可能还有未发送完毕的数据或尚未处理完的响应,因此对方先回复一个 ACK 确认包,待自己的全部数据发完后,再单独发送 FIN 请求关闭。两次 FIN 对应两次 ACK,总共四次交互。

3. 深入理解 TIME_WAIT 与 2MSL

主动发起关闭的一端(无论客户端还是服务端)在收到对方的 FIN 并发出最后的 ACK 之后,会进入 TIME_WAIT 状态,并强制停留 2MSL(Maximum Segment Lifetime,报文最大生存时间,通常为 60 秒到 120 秒)。

为什么必须等待 2MSL?
1. 确保被动关闭方能够收到最后的 ACK:若最后的 ACK 丢失,被动方会重传 FIN,2MSL 足以保证这个重传报文到达并被重新响应。
2. 让本次连接产生的所有旧报文从网络中消失:防止由于网络延迟导致的旧包在相同 IP 和端口的新连接中被错误接收。

4. 为什么线上会出现大量 CLOSE_WAIT?

CLOSE_WAIT 出现在被动关闭方。当收到对方的 FIN 后,操作系统协议栈会自动回复 ACK 并进入 CLOSE_WAIT,等待业务应用程序调用 close(socket)。

如果使用 ss -ant | grep CLOSE_WAIT 发现数量达到数千:说明你的代码存在连接泄露! 常见原因是 HTTP 客户端读取完响应体后没有执行 response.Body.Close(),或者连接池在出现异常时未调用回收逻辑。

本文作者:Alex Chen
本文链接:/posts/tcp-handshake-deepdive/
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。