四次挥手在做什么
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,通常出现在双方都主动关闭的场景,属于正常现象
- 关闭过程出现在固定间隔,多为空闲超时策略,与业务空闲时长对比即可确认