三次握手是什么
三次握手是 TCP 建立连接的过程:客户端发同步包、服务端回同步加确认、客户端再回一个确认,双方借此交换各自的初始序号并确认双向可达。为什么要三次而不是两次,是因为两个方向都要完成「我发了序号,并且你收到了」这件事:两次只能确认一个方向,另一次的可靠性无从判断,历史上重复的旧连接请求也可能被误当成新连接。
三步与状态
| 第一步 | 客户端发同步包,携带自己的初始序号,进入等待同步确认状态 |
|---|---|
| 第二步 | 服务端回同步加确认,携带自己的初始序号并确认客户端的,进入已收同步状态 |
| 第三步 | 客户端回确认,双方进入已建立状态,开始传输数据 |
| 关闭方向 | 连接关闭走另一套四次交互,不共用这三次握手的序号 |
| 序号作用 | 防止旧连接的重复报文被新连接误收 |
抓包观察三步
抓包观察三步
tcpdump -nn -c 3 'tcp port 8080' # 只抓 3 个包,正好对应握手
# 第一包 标志位为同步,序号是客户端初始值
# 第二包 标志位为同步加确认,序号是服务端初始值,确认号是客户端序号加一
# 第三包 只有确认,确认号是服务端序号加一
ss -tan state established | wc -l # 看当前已建立的连接数量抓包字段读法
| 字段 | 含义 | 正常与异常 |
|---|---|---|
| 标志位 | 同步表示建连请求,确认表示确认号有效 | 出现复位说明连接被拒绝或异常终止 |
| 序号 | 本方发送数据的起始编号 | 初始值应随机,可预测会带来注入风险 |
| 确认号 | 期望对方下一次发送的序号 | 第二步的确认号应等于客户端序号加一 |
| 状态列 | 套接字当前所处状态 | 长期停在半连接状态说明对方未收到最后确认 |
常见异常表现
- 连接超时没有响应:同步包被中间防火墙丢弃,而不是服务没启动
- 连接被拒绝:对方端口无监听,内核直接回复位包
- 握手很慢但能成功:中间设备限速或丢包,重传拖长了建立时间
- 大量半连接堆积:可能遭遇同步包洪水,也可能对端网络不稳
第三步确认丢失时,客户端已经认为连接可用,而服务端还停在半连接状态:服务端会重传第二个包,收到重复确认后照样完成建连,因此这种丢包通常表现为短暂延迟,而不是失败。
同步包被静默丢弃与端口无监听的表象完全不同:前者是长时间等待后超时,后者立刻被拒绝。排障时先看是超时还是拒绝,可以省下大量猜测。
建立时间为什么会变长
- 首包丢失会触发超时重传,建立时间从毫秒级变成秒级,用户感受非常明显
- 中间设备做深度检测会推迟转发,握手包被排队,表现为整体访问偏慢
- 服务端半连接队列满后会丢弃新的同步包,客户端只能持续重试
- 跨地域访问时往返时延本身就会把三次交互的总耗时放大
排查顺序
| 先看什么 | 原因 | 再看什么 |
|---|---|---|
| 是超时还是被拒绝 | 区分丢包与无监听 | 防火墙规则、安全组、进程状态 |
| 建立耗时分布 | 定位是否重传 | 抓包看是否有重复的同步包 |
| 服务端状态计数 | 判断队列是否溢出 | 队列参数与并发连接数 |