详解TCP四次挥手

前言

TCP 是全双工通信:

存在独立的上行通道(你发我收)、下行通道(我发你收),关闭连接时,两个方向的通道需要分别关闭,这就是「建立连接 3 次、断开连接 4 次」的根本原因。

复用上一篇讲的统一规则

1.控制标志位:

FIN:关闭本方发送通道,请求断开连接

ACK:确认报文,纯 ACK 不消耗序列号

2.序号消耗规则(和 SYN 完全一致):

SYN / FIN 控制报文:无数据,固定占用 1 个序列号

纯 ACK 报文不占用序列号

3.确认号万能公式:

ack=对方上一次seq+对方占用的字节/控制位数量

只要对方发了 FIN/SYN,我方确认号一定 +1

角色定义

主动关闭方:先调用 close() / 主动发起断开(可以是客户端,也可以是服务端,不固定)

被动关闭方:收到 FIN 后,被动响应关闭

初始状态

双方数据传输,都处于ESTABLISHED稳定通信状态

四次挥手整体流程总览

第一次挥手:主动方 → 被动方:我没数据要发了,请求关闭我的发送通道(FIN)

第二次挥手:被动方 → 主动方:收到你的关闭请求,我知道了(ACK 确认)

第三次挥手:被动方数据发完 → 主动方:我也没数据要发了,我也要关闭我的发送通道(FIN)

第四次挥手:主动方 → 被动方:收到,确认关闭,连接彻底销毁

分布讲解

我们假设:

主动关闭方为A

被动关闭方为B

A发送 FIN 序列号:x

B传输数据使用序列号:y

第一次挥手:A -> B(FIN报文)

主动方应用层调用 close() 系统调用,告知内核:不再发送任何数据。

TCP报文字段:

标志位:FIN=1,ACK=1

序列号:seq = x

无应用层数据

FIN 消耗 1 个序列号

主动方 A从 ESTABLISHED→FIN_WAIT_1(等待对方对 FIN 的 ACK 确认),

被动方 B保持 ESTABLISHED。

A 单方面关闭自己的写通道,A 再也不会发数据;但 TCP 全双工:A 仍然可以接收 B 发来的数据。

第二次挥手:B -> A(ACK确认报文)

B 内核收到 A 的 FIN 报文,校验合法,立即回复确认。

TCP报文字段:

标志位:ACK=1

确认号:ack=x+1(因为 A 的 FIN 占用 1 个序号,必须 + 1)

序列号:seq=y

无 FIN、无数据,纯 ACK 不消耗序号

被动方 B:ESTABLISHED→CLOSE_WAIT(半关闭状态,等待本机应用层调用 close)

主动方 A:FIN_WAIT_1→FIN_WAIT_2

此时进入TCP 半关闭状态:

A:不能发数据,但还能收 B 的数据

B:正常收发完全不受限,B 可以继续向 A 发送剩余业务数据

这一步只确认关闭 A 的写通道,不关闭 B 的写通道( 这就是为什么不能把第二次、第三次挥手合并的核心原因)。

第三次挥手:B->A(FIN+ACK 报文)

B 的应用层把剩余所有数据全部发送完毕,调用 close(),告知内核关闭自己的发送通道。

TCP报文字段:

标志位:FIN=1,ACK=1(连接一旦完成三次握手、进入 ESTABLISHED 之后,后续所有数据报文、挥手报文,一律必须 ACK=1,第三次挥手的 ACK=1 不是再确认一次,只是协议强制标配)

序列号:seq=w

确认号:ack=x+1(沿用上次确认号不变)

被动方 B:CLOSE_WAIT→LAST_ACK(最后一次确认,等待 A 回复最终 ACK)

主动方 A:保持 FIN_WAIT_2

B 也关闭了自己的写通道;至此,上下两个方向的发送通道全部关闭,双方都不能再发数据。

第四次挥手A->B(最终ACK报文)

A 收到 B 的 FIN 报文,回复最后一次确认。

TCP报文字段:

标志位:ACK=1

确认号:ack=w+1

序列号:seq=x+1

被动方 B:收到该 ACK 后 LAST_ACK→CLOSED(B 直接释放连接资源,彻底关闭)

主动方 A:FIN_WAIT_2→TIME_WAIT

主动关闭方不会立刻关闭,必须在 TIME_WAIT 状态停留2MSL时长。

问题

1:为什么断开连接需要四次挥手,不能像建连一样三次?

建立连接:

双方 SYN 同步 + ACK 确认可以合并为一个报文(第二次握手:SYN+ACK),所以 3 次。

断开连接:

TCP 全双工,两个方向关闭独立:

第一步:A 发 FIN 关闭自己写通道

第二步:B 先单独 ACK 确认(B 可能还有数据要发,不能立刻关)

第三步:B 数据发完,再发 FIN 关闭自己写通道

第四步:A 最终 ACK 确认

什么情况下会变成三次挥手断开?

当被动方没有任何剩余数据时:

B 收到 FIN 后,会把 ACK + FIN 合并为一个报文发送,四次挥手简化为三次挥手,属于特殊场景。

2.TIME_WAIT 状态为什么必须等待 2MSL?

MSL:报文最大生存时间,Linux默认30s,RFC标准60s。

2MSL两大核心作用:

1.保证最后一次 ACK 可靠到达对方

如果第四次挥手的 ACK 丢失,B 超时会重发 FIN;

A 处在 TIME_WAIT 仍可以重发 ACK,避免 B 一直重传。

2.等待网络中残留迟到报文彻底过期

等待过往连接的延迟、迷路报文全部失效;

防止旧连接的无效报文,干扰新建立的相同端口连接,造成数据错乱。

3.为什么是主动关闭方进入 TIME_WAIT,不是被动方?

如果被动方留 TIME_WAIT:

服务端一般固定端口,频繁重启服务会因大量 TIME_WAIT 端口占用,无法立刻监听;

主动方一般是客户端、随机端口,TIME_WAIT 对服务端影响最小,设计更合理。

4:大量 CLOSE_WAIT 状态堆积是什么问题?

原因:被动关闭方 应用层代码漏写 close ()

过程:

内核收到对方 FIN、回复了 ACK,进入 CLOSE_WAIT;

但业务代码不调用 close,内核永远不会发第三次挥手的 FIN;

后果:连接僵死、占用文件描述符,服务卡死。

5:四次挥手过程中可以传输数据吗?

第二次挥手后,B 处于 CLOSE_WAIT,依然可以正常发送业务数据给 A,直到业务数据全部发完才会发 FIN。

补充

暴力断开 RST 报文(异常场景)

正常是四次挥手优雅关闭;

如果出现:进程崩溃、端口直接关闭、连接超时、非法报文:

系统会直接发送 RST 重置报文,强制释放连接,跳过四次挥手,直接强行断开,不保证数据完整性。

相关推荐
白驹笙鸣1 小时前
HTTP(1)
网络·网络协议·http
IT菜鸟程1 小时前
漏洞修复案例:ArcGIS Server REST 服务目录敏感信息泄露
网络·安全·arcgis
X7x52 小时前
【网络技术】SVI/VLANIF:三层交换机的虚拟路由接口
网络·网络协议·信息与通信·svi·vlanif
发光小北2 小时前
Modbus TCP 转 CANopen 网关如何应用?
网络·网络协议·tcp/ip
你的保护色2 小时前
华为eNSP网络实验之IPsec协议学习
网络·学习·华为
AI生产力指南2 小时前
泛微·易秒办集成OpenClaw机器人:打造“能说会做”的智能助手
运维·网络·人工智能
威联通安全存储2 小时前
内存带宽解禁:TS-h3077AFU 闪存算力释放解析
网络
老毛肚3 小时前
Redis实战
网络
眷蓝天8 小时前
OSI七层模型
网络