← 返回题目列表

TCP 为什么要四次挥手?能不能三次?

高频 中等 第 13 / 30 题 更新于 2026/07/28
TCP四次挥手连接管理

简化版

四次挥手是断开 TCP 连接的过程。因为 TCP 是全双工(两个方向独立),关闭要两个方向各关一次:一方发 FIN 说「我没数据要发了」,另一方 ACK 确认;反过来另一方也发 FIN、对方再 ACK,共四次。之所以是四次而不是三次,是因为被动方收到 FIN 后,可能还有数据没发完,所以它的 ACK 和 FIN 通常不能合并,要分两次发。

详细版

四次挥手过程(假设客户端主动关闭):

  1. 客户端 → FIN:客户端发 FIN,表示「我不再发送数据了」,进入 FIN_WAIT_1
  2. 服务端 → ACK:服务端确认,进入 CLOSE_WAIT;客户端收到后进入 FIN_WAIT_2。此时服务端到客户端方向还能发数据(半关闭状态)。
  3. 服务端 → FIN:服务端把剩余数据发完后,也发 FIN,进入 LAST_ACK
  4. 客户端 → ACK:客户端确认,进入 TIME_WAIT;服务端收到后进入 CLOSED。客户端等待 2MSL 后也进入 CLOSED

为什么是四次不是三次:三次握手时,服务端的 SYNACK 能合并成一个包(SYN+ACK),因为建连时它没有别的数据要处理。但挥手时,服务端收到客户端的 FIN 后,它可能还有数据要发给客户端,所以只能先单独回 ACK(我知道你要关了),等自己数据发完再发 FIN。ACK 和 FIN 分开,就成了四次。

完整版教学

一、根源:TCP 全双工,关闭要「各关各的」

TCP 连接是全双工的——A→B 和 B→A 是两条独立的数据通道。所以「关闭连接」本质上是关闭两个方向,每个方向都要「一方声明关闭(FIN)+ 另一方确认(ACK)」。两个方向 × 两步 = 四次。

对比三次握手:建连时要同步双方的初始序列号,双方各需一次 SYN + 一次 ACK,也是四个动作,但服务端的 ACK 和 SYN 能合并成一个包,所以三次。挥手时服务端的 ACK 和 FIN 常常不能合并,所以四次。区别就在于「能不能把 ACK 和 FIN/SYN 合并」。

二、半关闭:为什么 ACK 和 FIN 要分开

第 2、3 步之间的状态叫半关闭(half-close):客户端已经不再发数据(它的 FIN 发过了),但服务端仍可以继续向客户端发送数据。

这正是四次的关键——服务端收到客户端 FIN 时,可能手头还有数据没发完。它必须:

  • 先回 ACK:告诉客户端「你的关闭请求我收到了」,别让客户端超时重发 FIN;
  • 继续把剩余数据发完;
  • 再发 FIN:等自己也没数据了,才声明关闭。

如果服务端没有剩余数据,理论上 ACK 和 FIN 可以合并成三次(这也是一种优化,实际中「延迟确认」有时会让它们合并)。但一般情况下要预留「发完剩余数据」的余地,所以标准是四次。

三、TIME_WAIT:主动关闭方为什么要等 2MSL

主动关闭方(这里是客户端)发出最后一个 ACK 后,不会立即 CLOSED,而是进入 TIME_WAIT,等待 2MSL(MSL = 报文最大生存时间)才真正关闭。原因有两个:

  1. 保证最后的 ACK 能到达对方:万一这个 ACK 丢了,服务端会超时重发 FIN,客户端还在 TIME_WAIT 就能重新回 ACK。如果客户端直接关了,重发的 FIN 就没人应答,服务端一直卡在 LAST_ACK。
  2. 让本次连接的旧数据包在网络中彻底消失:等 2MSL(一来一回的最大时间)后,旧连接的残留报文都过期了,避免它们「串扰」到后续用相同端口的新连接。

TIME_WAIT 和 CLOSE_WAIT 是两个不同角色的状态,也是高频考点,详见「TIME_WAIT 和 CLOSE_WAIT 的区别」那道题。

四、异常情况:如果不按规矩挥手

  • 服务端不发 FIN(一直不关):客户端会长期停在 FIN_WAIT_2。系统一般有超时机制回收。
  • 大量 CLOSE_WAIT 堆积:说明服务端收到了 FIN 却迟迟不关闭连接——通常是代码 bug(没有正确 close() socket)。这是排查连接泄漏的重要信号。
  • 直接 RST:如果一方想强制中断(如进程崩溃、SO_LINGER 设 0),会发 RST 直接重置连接,跳过四次挥手,另一方会收到「connection reset」。

五、常见误区

  • ❌ 以为挥手一定是四次、握手一定是三次是「规定」——本质都是四个动作,区别在能否合并 ACK。
  • ❌ 以为发完 FIN 就不能收数据——半关闭下,主动方发完 FIN 仍能接收对方数据。
  • ❌ 把 TIME_WAIT 当成有害要消灭——它是保证可靠关闭的必要机制,大量堆积才需调优。
  • ❌ 大量 CLOSE_WAIT 以为是对端问题——CLOSE_WAIT 在自己这侧,通常是自己没 close。

六、常见误区与追问

考点正确口径
第一次主动方发送 FIN,表示自己不再发送数据
第二次被动方 ACK,表示收到关闭请求
第三次被动方发送 FIN,表示自己也发完了
第四次主动方 ACK,并进入 TIME_WAIT
A -> FIN -> B
A <- ACK <- B
A <- FIN <- B
A -> ACK -> B
A enters TIME_WAIT

四次挥手的根源是 TCP 全双工:两个方向的数据通道要分别关闭。

  • 误区:TCP 关闭必须总是四个独立报文。 被动方 ACK 和 FIN 有时可合并,但逻辑上仍是两个方向分别关闭。
  • 误区:收到 FIN 就不能再收数据。 收到对方 FIN 只表示对方不再发送,自己仍可继续发送剩余数据。
  • 误区:TIME_WAIT 是服务器特有状态。 TIME_WAIT 在主动关闭方,客户端或服务器都可能进入。
  • 追问:为什么不能三次挥手? 被动方收到 FIN 后可能还有数据没发完,ACK 和自己的 FIN 不能总是立即合并。
  • 追问:TIME_WAIT 为什么要等 2MSL? 确保最后 ACK 可重传,并让旧连接报文在网络中自然消失。
  • 追问:CLOSE_WAIT 多说明什么? 通常说明应用收到关闭后没有及时 close,属于应用层资源释放问题。

七、加强记忆

TCP 全双工,关闭要关两个方向,每个方向「FIN + ACK」,共四次。四次而非三次,是因为被动方收到 FIN 后可能还有数据要发,只能先单独回 ACK、数据发完再发 FIN,两者无法合并。主动关闭方最后等 2MSL(保证末尾 ACK 送达 + 让旧报文消散)才真正关闭。