优雅关闭与截断的区别
close_notify 是 TLS 的优雅关闭通知(Alert 描述码 0)。正常流程是先发一条 close_notify,再关 TCP,对端由此知道「数据到此为止」,不会把半截数据当完整数据。如果只看到 TCP FIN/RST 而没有 close_notify,那就是截断关闭:应用层可能已经收到一部分数据,却无法判断完整性,大文件下载尾部损坏、响应体不完整常由此而来。
基本信息
| 关键字段 | tls.alert_message.desc == 0 |
|---|---|
| 对照信号 | TCP FIN、TCP RST、超时静默断开 |
| 方向 | 双向都可能发,单侧发完即可半关闭 |
| 可见性 | 加密层内,1.3 需解密才能确认 |
典型使用场景
- 下载文件损坏或校验失败:确认服务端是否优雅关闭
- 排查 curl 报错:传输提前结束与连接被重置指向不同问题
- 长连接复用:连接池回收时是否走了正常关闭流程
- 定位中间设备提前断开:无 close_notify 的被动中断
- 对比正常会话与异常会话的收尾差异,作为报告证据
对照检查
对照检查
tshark -r t.pcap -Y "tls.alert_message.desc==0" -T fields -e frame.number -e ip.src
# 有 close_notify:优雅关闭
tshark -r t.pcap -Y "tcp.flags.fin==1 || tcp.flags.reset==1" -T fields -e frame.number -e ip.src -e tcp.flags.reset
# 只出现 FIN/RST 而无 close_notify:截断关闭,RST 更粗暴,双向数据都可能丢关闭方式对照
| 收尾信号 | 含义 | 影响 |
|---|---|---|
| close_notify 后 FIN | 双方知情,数据边界完整 | 正常,可按完整数据处理 |
| 仅 TCP FIN | 未发通知,对端可能当作截断 | 应用层报数据不完整 |
| TCP RST | 强制中断,发送缓冲可能被丢弃 | 双向都可能丢数据 |
| 超时无收尾 | 静默断开,双方都不知情 | 结合 keepalive 与超时配置判断 |
部分老实现或简单 HTTP 服务端不发 close_notify(历史兼容原因,协议也只要求收到后回复)。出现频率低时按实现基线判断,不要一律当故障;频率突增才值得追。
close_notify 位于加密层,TLS 1.3 中要确认必须解密。未解密时只能靠 TCP 收尾形态推测,结论要标注不确定性,避免把推测写进报告结论。
排查顺序
- 先在客户端抓包确认收尾信号:是 close_notify、单独 FIN,还是 RST
- 再确认应用层是否按长度或摘要校验完整性,区分「真的少数据」与「直接失败」
- 检查服务端日志有无主动中断记录:超时、鉴权失败、进程重启都会产生中断
- 检查中间设备会话表老化时间,被动断开常表现为固定间隔出现的 RST
- 对比同一时间窗内其他会话,判断是个例还是成片,成片时优先怀疑设备与链路