四次挥手是什么
关闭连接是全双工的:一方发出结束标志只表示「我没有数据要发了」,对方确认之后仍然可以继续发送数据,这种状态叫半关闭;等对方也发完自己的结束标志,连接才彻底关闭。因此关闭通常需要四个报文:结束标志、确认、对方的结束标志、最后的确认。之所以不是两次,是因为两个方向的数据流要各自独立关闭,否则会出现一端已经无法发送而另一端还有数据待发的错乱。
基本信息
| 触发 | 任一方调用关闭并发送结束标志 |
|---|---|
| 主动方状态 | 发送后等待确认,再等待对方结束标志,最后进入停留期 |
| 被动方状态 | 收到结束标志后进入等待本端关闭的状态,再等待最后确认 |
| 关键点 | 收到对方结束标志并不意味着可以立即释放,必须先处理完自己的数据 |
| 合并情况 | 对方已无数据可发时,确认与结束标志常被合并成一个报文 |
典型使用场景
- 排查连接长时间不释放:定位是应用没有及时关闭,还是对端没有发完
- 排查随机出现的连接被重置:常见于本端未读完残留数据就关闭
- 压测中观察连接生命周期:确认短连接是否真的被及时回收
- 服务优雅下线:先停止接收新请求,再等待已有请求处理完再关闭
- 定位文件描述符泄漏:连接数量持续上升往往能从状态分布看出来
抓包观察关闭过程
抓包观察关闭过程
tcpdump -nn -c 8 'tcp port 8080' # 抓一小段,能看到结束标志与确认的交互
# 第一包带结束标志,表示主动方不再发送数据
# 第二包是确认,被动方此时进入等待本端关闭的状态
# 第三包是被动方的结束标志,第四包是最后的确认
ss -tan state close-wait | wc -l # 统计卡在本端未关闭状态的连接数状态流转怎么读
| 角色 | 状态顺序 | 含义 |
|---|---|---|
| 主动方 | 发送后等待确认,再等待对方结束,最后进入停留期 | 走完四次交互后还需停留一段时间才彻底释放 |
| 被动方 | 等待本端关闭,再等待最后确认 | 应用不关闭就会一直停在这里 |
| 合并情形 | 看起像三次交互 | 对方无数据待发时,确认与结束标志被合并 |
| 同时关闭 | 双方同时发起 | 属于少见情形,双方各自进入等待对方结束的状态 |
排查要点
- 统计各状态连接数量,卡在本端未关闭状态的大量连接几乎总是应用没有关闭
- 连接被重置优先怀疑本端还有未读数据就调用关闭,内核会用复位响应
- 偶发的关闭延迟属于正常现象,重点看是否持续堆积而不是单次波动
- 优雅关闭要留出处理时间,直接杀掉进程会让正在处理的请求全部失败
被动方收到对方结束标志后如果应用迟迟不关闭连接,就会长期停在等待本端关闭的状态。这是应用层泄漏最典型的信号,调网络参数治不了,必须回到代码与连接池配置。
主动关闭方在走完交互后还要停留两倍最大报文生存时间才能彻底释放,这是为了确保最后的确认能重传,并让旧连接的残留报文过期,属于协议正确性的一部分。