TCP 流分析82 条

TCP 四次挥手判读

关闭流程:主动方 FIN → 对端 ACK → 对端 FIN → 主动方 ACK;理解半关闭(单向 FIN)与谁先关闭,定位"连接迟迟不释放"的问题。

四次挥手在做什么

TCP 连接的关闭是双向的:主动关闭方发出 FIN 表示本端不再发送数据,对端回 ACK 确认,此时连接处于半关闭状态,反向仍可以继续传数据;对端数据发完后也发一个 FIN,主动方再回 ACK,连接才彻底结束。理解半关闭是判读的关键:只看到一半的关闭流程并不代表连接异常。抓包判读关注三件事:谁先发起关闭、FIN 到 FIN-ACK 的间隔、以及最后由哪一侧进入等待状态。

基本信息

抓取写法tcp[tcpflags] & (tcp-fin|tcp-rst) != 0
显示过滤tcp.flags.fin == 1
关键状态FIN-WAIT、CLOSE-WAIT、LAST-ACK、TIME-WAIT
观察命令ss -tan 查看各状态连接计数
强制关闭RST 结束的连接没有完整挥手过程

关闭流程逐包读法

报文含义判读要点
FIN 加 ACK主动方表示不再发送数据发起方是主动关闭方,多出现在短连接客户端
ACK对端确认收到 FIN连接进入半关闭,反向数据仍可继续
FIN 加 ACK(反向)对端也发完数据后关闭两次 FIN 之间的时间差反映对端数据处理耗时
最后的 ACK主动方确认对端关闭抓包点不在主动方时可能看不到这个报文
RST强制终止没有四次挥手过程,需单独判断来源

典型使用场景

  • 定位连接迟迟不释放:确认是哪一侧没有发 FIN 或没有确认
  • 排查应用连接泄漏:大量连接停在等待对端关闭的状态
  • 分析短连接行为:观察是否每次都完整挥手,还是有重置打断
  • 验证连接池配置:看空闲连接是被复用还是被周期性关闭
  • 核对负载均衡空闲超时:连接在固定空闲时长后被主动断开

抓取与查看

抓取与查看
tcpdump -i eth0 -nn 'tcp[tcpflags] & (tcp-fin|tcp-rst) != 0' -c 20   # 抓关闭与复位
tcpdump -i eth0 -nn 'tcp[tcpflags] = tcp-fin|tcp-ack' -c 10           # 只看关闭确认
ss -tan | awk '{print $1}' | sort | uniq -c | sort -rn                 # 统计各状态数量
ss -tan state close-wait | wc -l                                      # 被动关闭堆积数量
抓包里看不到最后那个确认报文是正常现象:它可能已经发出,但抓包点不覆盖那条路径。判读关闭流程时以自己能看到的范围为限,不要据此判断连接异常。
用重置结束的连接没有完整挥手,套用四次挥手的模板会得出错误结论。看到重置要先判断它出现在建连阶段还是传输阶段,两者的原因完全不同。

定位不释放的连接

定位不释放的连接
ss -tanp state close-wait | head -20        # 本端未关闭的连接与对应进程
ss -tanp state fin-wait-2 | head -20        # 等待对端关闭的连接
ss -tnp | grep ESTAB | wc -l                # 存活连接总数,与业务预期对比

判读要点

  • 主动关闭方会经过等待状态,短连接特别多时该状态数量自然偏高
  • 只发 FIN 而长时间没有反向 FIN,说明对端应用没有及时关闭连接
  • 两侧几乎同时发 FIN,通常出现在双方都主动关闭的场景,属于正常现象
  • 关闭过程出现在固定间隔,多为空闲超时策略,与业务空闲时长对比即可确认

易错点

  • 把半关闭误判成连接异常,单向 FIN 是协议允许的正常状态
  • 用四次挥手的模板解读重置报文,会得出与实际不符的结论
  • 抓包点不覆盖全部路径时以为缺少的报文不存在,需要说明抓包范围
  • 大量等待对端关闭的连接不一定是网络问题,多与本端应用未及时关闭有关
  • 关闭过程缺失导致连接数持续增长时,应结合进程与连接状态定位而非只看抓包

数据来源与参考

  • RFC 9293(连接终止)
  • Wireshark User's Guide
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌