📄 计算机基础 🟢 入门 ⏱ 8 分钟

👋 TCP 四次挥手:连接是怎么断开的

FIN → ACK → FIN → ACK,全双工独立关闭。为什么是四次?TIME_WAIT 又为什么等 2MSL?

1

四次挥手在干什么

🎯 终止连接

TCP 四次挥手是终止连接的过程。

因为 TCP 是全双工通信,两个方向要各自独立关闭发送通道,所以需要四次报文交换。

🔑 记忆口诀

FIN → ACK → FIN → ACK

四步挥手不乱来,全双工独立关闭。

2

完整流程

① FIN客户端发 FIN → FIN_WAIT_1
➜
② ACK服务端回 ACK → CLOSE_WAIT
➜
③ FIN服务端数据发完发 FIN → LAST_ACK
➜
④ ACK客户端回 ACK → TIME_WAIT(2MSL)
👋 四次后双方关闭,客户端最后 TIME_WAIT 等 2MSL
🎬 四次挥手报文交换(客户端主动关闭)
① 客户端 → 服务端
FIN, seq=x → 客户端 FIN_WAIT_1(表示我这边数据发完了)
② 服务端 → 客户端
ACK, ack=x+1 → 服务端 CLOSE_WAIT,客户端 FIN_WAIT_2(服务端可能还有数据要发)
③ 服务端 → 客户端
服务端数据发完 → 发 FIN, seq=y → LAST_ACK
④ 客户端 → 服务端
ACK, ack=y+1 → 客户端 TIME_WAIT(2MSL),服务端 CLOSED
3

为什么是四次,不是三次

🔀 全双工要独立关

第一次挥手关闭了主动方的发送通道,但被动方可能还有数据要发。

所以 ACK 和 FIN 要分开发送:先回 ACK 告诉「收到你的 FIN」,等服务端数据发完了再发 FIN。

这就多出一次,变成四次。

🔄 什么时候能三次

如果被动方也没有数据要发,理论上可以合并成三次挥手。

TCP 的延迟确认机制可能让这种情况发生(ACK 和 FIN 一起发)。

🎬 为什么不能 ACK 和 FIN 一起发
场景
客户端说「我数据发完了」,但服务端还有最后一批数据没发完
如果一起发
服务端收到 FIN 立刻回 ACK+FIN 关闭 → 那批还没发完的数据就丢了!
所以分开
先回 ACK(收到你的 FIN,我先把手头数据发完)→ 发完后我再发 FIN → 你回 ACK
4

TIME_WAIT 为什么要等 2MSL

⏳ TIME_WAIT 的意义

主动关闭方收到对方 FIN、回 ACK 后进入 TIME_WAIT,持续 2MSL(最大报文生存时间的两倍,约 2-4 分钟)。

两个目的:
① 保证最后一个 ACK 被对方收到(若丢失对方会重传 FIN)
② 保证旧连接报文在网络中消失,不干扰新连接。

⚠️ 高并发的问题

TIME_WAIT 会占用端口资源。

高并发服务端可能出现大量 TIME_WAIT,端口耗尽。

优化:SO_REUSEADDR 重用端口、用连接池、调整 tcp_tw_reuse。

🎬 为什么最后一个 ACK 不能丢
正常
客户端回 ACK → 服务端收到 → 服务端 CLOSED,连接正常关闭
若 ACK 丢了
服务端等不到 ACK → 超时重发 FIN → 客户端此时还在 TIME_WAIT,能再回 ACK
2MSL 意义
留出足够时间让最后一个 ACK 能到达,也确保旧报文在网络中消亡,不污染新连接
5

TIME_WAIT / CLOSE_WAIT 排查

⏳
大量 TIME_WAIT

主动关闭方常见,高并发下端口耗尽。开启 SO_REUSEADDR、用连接池、调整 tcp_tw_reuse。注意 tcp_tw_recycle 在 Linux 4.12 已移除。

🐛
大量 CLOSE_WAIT

被动关闭方代码问题——通常没调用 close() 或没正确处理 socket 异常。CLOSE_WAIT 过多 → 查代码连接释放逻辑。

🔀
同时关闭(三次)

双方同时发 FIN、各回 ACK,只需三次报文交换即可关闭。

一句话总结

TCP 四次挥手 = FIN → ACK → FIN → ACK,因为全双工要独立关闭两个方向(被动方可能还有数据要发,所以 ACK 和 FIN 分开发)。主动方最后进入 TIME_WAIT(2MSL):保证最后一个 ACK 到达、让旧报文在网络中消失。排查:大量 TIME_WAIT 用 SO_REUSEADDR/连接池;大量 CLOSE_WAIT 一般是代码没 close()。

🎤 面试问答 · 口语化回答
四次挥手是 TCP 面试的高频题,尤其 TIME_WAIT 和状态排查常被深挖:
面试官TCP 四次挥手的过程是怎样的?
你

假设客户端主动关闭。第一次客户端发 FIN 表示数据发完,进入 FIN_WAIT_1;第二次服务端回 ACK,进入 CLOSE_WAIT,客户端进 FIN_WAIT_2,这时候服务端可能还有数据要发;第三次服务端数据发完,发 FIN 进 LAST_ACK;第四次客户端回 ACK,进入 TIME_WAIT 持续 2MSL,服务端收到后 CLOSED,TIME_WAIT 结束后客户端也 CLOSED。

💡 加分点:能同步说出 CLOSE_WAIT、LAST_ACK、TIME_WAIT 这些状态,说明你完整掌握,很加分。
面试官为什么四次挥手而不是三次?
你

因为 TCP 是全双工的,两个方向的连接要独立关闭。第一次挥手只关闭了主动方的发送通道,但被动方可能还有数据要发,所以它不能立刻关闭,而是先回 ACK 表示收到你的 FIN,等它自己的数据发完了再发 FIN。这样 ACK 和 FIN 分开发,就多了一次变成四次。如果被动方也没数据要发,理论上可以合并成三次。

💡 加分点:用「被动方还有数据要发,所以 ACK 和 FIN 分开发」这个点,比笼统说「全双工」更有说服力。
面试官为什么要有 TIME_WAIT 状态?为什么是 2MSL?
你

TIME_WAIT 是主动关闭方在收到对方 FIN、回完 ACK 后进入的状态,持续 2MSL。两个目的:一是保证最后一个 ACK 能被对方收到,如果 ACK 丢了对方会重传 FIN,而 TIME_WAIT 期间客户端还能再回 ACK;二是保证旧连接的所有报文在网络中消失,不干扰后续的新连接。2MSL 是因为 MSL 是最大报文生存时间,2MSL 能覆盖 FIN 重传和 ACK 到达的最长路径。

💡 加分点:能讲出「保证 ACK 到达 + 让旧报文消亡」两个目的,并解释 2MSL 的构成,体现真正理解而非背诵。
📝 读完打卡 · 写下你的收获 读完了?来打卡吧
用一句话写下你从这篇学到的最大收获,检验自己是否真的懂了 👇
⏱ 00:00 🔥0分