一句话总结:
TCP四次挥手就像两人告别——先说要走(FIN),对方确认(ACK),等对方也说要走(FIN),最后再确认(ACK),确保双方都安心离开!
一、流程拆解(好友告别版)
假设你和朋友 可靠地 结束通话,步骤如下:
1. 第一次挥手(客户端 → 服务器)
- 动作:你说:“我这边说完了,准备撤了! ”(发送
FIN包)。 - 意义:客户端主动关闭,进入
FIN_WAIT_1状态,等待确认。
2. 第二次挥手(服务器 → 客户端)
- 动作:朋友回答:“收到!但我还有点话要说... ”(回复
ACK包)。 - 意义:服务器确认收到关闭请求,进入
CLOSE_WAIT状态,继续处理剩余数据。
3. 第三次挥手(服务器 → 客户端)
- 动作:朋友说完后,也告别:“我也说完了,拜拜! ”(发送
FIN包)。 - 意义:服务器主动关闭,进入
LAST_ACK状态,等待最后确认。
4. 第四次挥手(客户端 → 服务器)
- 动作:你最后确认:“好的,彻底拜拜! ”(发送
ACK包)。 - 意义:客户端进入
TIME_WAIT状态(等2倍报文寿命),确保对方收到ACK。
二、为什么必须四次?三次行不行?
关键点:TCP是全双工通信,每个方向独立关闭!
- 你的关闭(发FIN)和 对方的关闭(发FIN)是两件事,需分别确认。
- 如果合并第二次和第三次挥手(ACK+FIN一起发),可能对方还有数据没传完!
三、技术细节(包结构)
- 第一次挥手:
Flags=FIN, SEQ=序列号X - 第二次挥手:
Flags=ACK, ACK=X+1 - 第三次挥手:
Flags=FIN+ACK, SEQ=序列号Y, ACK=X+1 - 第四次挥手:
Flags=ACK, ACK=Y+1
示例:
客户端 → 服务器:FIN(SEQ=100)
服务器 → 客户端:ACK(ACK=101)
(服务器处理剩余数据...)
服务器 → 客户端:FIN+ACK(SEQ=300, ACK=101)
客户端 → 服务器:ACK(ACK=301)
四、关键状态解析
-
TIME_WAIT(客户端) :
-
等待时长:2倍报文最大存活时间(2MSL,通常2分钟)。
-
作用:
- 确保最后一个ACK送达,若丢失可重传。
- 让旧连接的报文在网络中消亡,防止与新连接混淆。
-
-
CLOSE_WAIT(服务器) :
- 问题场景:若代码未正确关闭连接,会导致大量
CLOSE_WAIT堆积,占用资源。
- 问题场景:若代码未正确关闭连接,会导致大量
五、常见问题解答
1. 为什么有时候连接关闭很慢?
- 服务器未及时发FIN:可能还在处理数据或代码未正确调用
close()。 - 客户端卡在TIME_WAIT:需等待2MSL,可通过调整内核参数缩短。
2. 大量TIME_WAIT危害?
-
占用端口资源:客户端端口耗尽,无法发起新连接。
-
解决方案:
- 复用连接(HTTP Keep-Alive)。
- 调整
net.ipv4.tcp_tw_reuse参数。
3. 如果第四次挥手ACK丢了怎么办?
- 服务器重传FIN:客户端在TIME_WAIT期间收到后,会重发ACK。
六、总结口诀
“四次挥手断连接,双向关闭要确认。
一FIN来二ACK,三FIN四ACK跟。
TIME_WAIT防丢包,CLOSE_WAIT查代码。
连接资源及时放,网络畅通无烦恼!”