0
0
0

TCP 三次握手、四次挥手与 TIME_WAIT、CLOSE_WAIT

2026-10-28
文章摘要
|

一、TCP 三次握手

TCP 是面向连接、可靠的、基于字节流的传输层协议。

客户端                        服务端
   |                             |
   |----------- SYN ------------>| ① 请求建立连接
   |                             |
   |<-------- SYN + ACK ---------| ② 确认请求,同时同步序列号
   |                             |
   |----------- ACK ------------>| ③ 确认连接建立
   |                             |
 ESTABLISHED                 ESTABLISHED

三次握手的作用是同步初始序列号、确认双方能够建立连接,并避免历史失效的连接请求造成错误连接。

二、TCP 四次挥手

假设客户端主动关闭 TCP 连接,服务端被动关闭。

客户端(主动关闭)                服务端(被动关闭)
       |                                |
  ESTABLISHED                      ESTABLISHED
       |                                |
       |------------- FIN ------------->| ① 请求关闭
       |                                |
   FIN_WAIT_1                          |
       |                                |
       |<------------ ACK --------------| ② 确认收到
       |                                |
   FIN_WAIT_2                      CLOSE_WAIT
       |                                |
       |                         等待应用关闭连接
       |                                |
       |<------------ FIN --------------| ③ 服务端请求关闭
       |                                |
       |                             LAST_ACK
       |                                |
       |------------- ACK ------------->| ④ 最后确认
       |                                |
   TIME_WAIT                         CLOSED
       |
   等待 2MSL
       |
     CLOSED

为什么通常需要四次挥手?

因为服务端收到 FIN 后,可能还有数据需要发送,因此需要先回复 ACK,等数据发送完毕后,再发送 FIN。

如果服务端立即准备关闭,也可能将 ACK 和 FIN 合并发送。

三、CLOSE_WAIT

CLOSE_WAIT 是被动关闭方收到 FIN 并确认后,等待本地应用关闭连接的状态。

常见原因:

  • Socket 没有正确关闭。

  • Java 异常分支遗漏资源释放。

  • Netty EventLoop 被阻塞。

  • 开启 TCP 半关闭后,没有正确完成关闭流程。

Linux 查看:

ss -tanp state close-wait

CLOSE_WAIT 长时间大量堆积,应重点检查应用连接关闭逻辑。

四、TIME_WAIT

TIME_WAIT 是主动关闭方发送最后一个 ACK 后进入的等待状态。

为什么等待 2MSL?

  1. 最后一个 ACK 可能丢失,需要能够处理服务端重传的 FIN。

  2. 避免旧连接中的延迟报文干扰后续复用相同四元组的新连接。

如果 TIME_WAIT 期间收到有效的重传 FIN:

客户端                           服务端
   |                                |
   |<------------ FIN --------------| LAST_ACK
   |                                |
   |------------- ACK --X           | ACK 丢失
   |                                |
 TIME_WAIT                           |
   |                                |
   |<------------ FIN --------------| 重传 FIN
   |                                |
   |------------- ACK ------------->|
   |                                | CLOSED
 TIME_WAIT
   |
 重新计时 2MSL
   |
 CLOSED

注意:TIME_WAIT 是状态,2MSL 是等待时长。收到有效的重传 FIN 后,客户端仍处于 TIME_WAIT,并重新计时。

五、TCP 关闭状态总结

状态

所属方(典型情况)

说明

FIN_WAIT_1

主动关闭方

已发送 FIN,等待确认

FIN_WAIT_2

主动关闭方

FIN 已被确认,等待对方 FIN

CLOSE_WAIT

被动关闭方

收到 FIN,等待本地应用关闭

LAST_ACK

被动关闭方

已发送 FIN,等待最后 ACK

TIME_WAIT

主动关闭方

发送最后 ACK 后等待 2MSL

CLOSED

双方

连接关闭

六、面试重点总结

1. 为什么三次握手、四次挥手?

建立连接时 SYN 和 ACK 可以合并发送;关闭连接时被动方可能还有数据需要发送,ACK 和 FIN 通常分开发送。

2. CLOSE_WAIT 是什么?

被动关闭方收到 FIN 并回复 ACK 后,等待应用关闭连接。

3. LAST_ACK 是什么?

被动关闭方发送 FIN 后,等待最后一个 ACK。

4. TIME_WAIT 为什么等待 2MSL?

为了处理最后 ACK 丢失导致的 FIN 重传,以及减少旧连接延迟报文对新连接的影响。

5. CLOSE_WAIT 大量堆积如何处理?

先使用 ss 定位进程和端口,再检查线程堆栈、Netty Channel 生命周期与应用连接关闭逻辑。

核心记忆:

  • FIN_WAIT_1:主动方发送 FIN,等确认。

  • FIN_WAIT_2:主动方等对方 FIN。

  • CLOSE_WAIT:被动方等自己应用关闭。

  • LAST_ACK:被动方等最后 ACK。

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或者给予支持!

评论