断线重连后出现TCP Dup ACK:序列号不一致问题排查求助
网线拔插测试后TCP连接仅存在重复ACK的异常排查
测试与抓包基础信息
- 网络架构:Device 1 ↔ Switch 1 ↔ Switch 2 ↔ Device 2
- 测试目标:验证中间链路物理断连恢复后,设备端TCP连接的自动重连能力
- 抓包关键时间节点:
- 序号1-9的报文为链路连通状态下的正常双向通信
- 9号包与10号包的时间间隔为Switch1与Switch2之间的网线拔出断网时段
- 10号包为Device 1发出的业务数据报文,全程未收到对端对应ACK
- 11、12号包为断网期间Device 2发出的TCP Keep-Alive探测报文
- 12号包与13号包的时间间隔为网线插回、链路恢复连通时段
- 13号包为Device 1对最后一条Keep-Alive报文的正常ACK,交互逻辑符合预期
- 13号包之后的所有抓包报文仅存在TCP Dup ACK
- 已观测的偏差点:Device 1本地维护的自身发送序列号为49,Device 2侧识别到的对端有效接收序列号最高为37,且Device 1的TCP协议栈不支持快速重传机制
异常成因与问题定位
序列号偏差的产生逻辑
TCP协议中,双方维护的序列号边界仅基于实际收到并确认的字节数计算,不存在主观随意设置的偏移:
- 断网期间Device 1发出的10号包(对应本地计算的49序列号)因为中间链路断开,从未到达Device 2,因此Device 2的接收边界始终停留在断网前最后一次收到的序列号37,不会因为Device 1本地的发送进度而同步更新。
- 链路恢复后,Device 2收到任何和自身期望序列号(37)不匹配的报文时,按照TCP规范会触发重复ACK,核心作用是告知对端“当前我能接收的下一个起始序列号是37,请补发从37开始的缺失内容”。这个动作是Device 2的合规正常响应,不存在协议栈异常。
问题死锁的触发原因
当前抓包持续出现重复ACK、连接无法恢复的状态,是两个因素叠加导致的:
- 首先排除Device1序列号逻辑异常的误判:Device1本地从序列号49开始发送,是完全符合TCP规则的行为——它是根据“本地已发送未被确认的字节数”累加计算的发送序号,不存在“未收到ACK就默认把发送序号设为49”的逻辑错误。
- 核心问题来自Device1的TCP栈合规性缺陷:按照TCP标准实现,连续收到3个及以上重复ACK时,会触发快速重传机制,直接按照对端ACK指定的起始序列号补发缺失内容,无需等待本地重传定时器超时。但因为Device1不支持快速重传,它会将所有收到的重复ACK判定为“之前发送的49序列号报文未被对端接收”,不会主动调整发送序号去匹配Device2期望的37序列号。
- 最终形成交互死锁:Device1持续等待自身重传定时器超时,就算超时后重传的还是49序列号的内容,依然会被Device2判定为乱序报文,继续触发重复ACK;而Device2因为始终收不到37到48区间的缺失内容,就会一直发送重复ACK,两个状态循环往复,在抓包上就表现为只有重复ACK、连接无法恢复正常数据传输。
最终结论
- 不存在Device1协议栈“随意设置默认发送序列号为49”的异常,该行为是TCP正常的发送序号计算逻辑。
- Device2侧的重复ACK响应完全符合协议规范,不存在异常。
- 问题的根因是Device1的TCP栈缺失快速重传能力,在链路中断导致报文丢失、双方序列号边界不匹配时,无法快速补发缺失内容,最终陷入交互死锁。
内容的提问来源于stack exchange,提问作者Philipp Seif
相关产品推荐
相关产品推荐

