本文目录导读:

- 超时重传 —— 最原始、最可靠的检测
- 快速重传 —— 更积极的检测
- Forward ACK (FACK) —— 更精细的检测
- Selective ACK (SACK)—— 高效处理连续丢包
- 时间戳选项 —— 更精确的 RTT/RTO 计算
- 总结与对比
- 实际开发或排查中如何观察丢包?
TCP 通过多种机制来检测丢包,主要分为被动检测和主动检测两大类,核心原理是依赖于序列号和确认号。
以下是 TCP 丢包检测的主要方法,从最常见到较详细:
超时重传 —— 最原始、最可靠的检测
这是 TCP 最基本的丢包检测机制,基于一个定时器。
- 原理:
- 发送方发送一个数据段(Segment),并启动一个重传计时器。
- 发送方在计时器到期前,等待接收方发回的确认包(ACK)。
- 如果计时器超时,仍未收到对应的 ACK,发送方就默认该数据段丢失。
- 关键参数:
- RTO:重传超时时间,其计算依赖于 RTT,TCP 会动态测量 RTT,并计算一个平滑的 RTT 值和偏差,以自适应地调整 RTO 值。
- 优点:简单,能处理任何原因的丢包(如拥塞、线路故障)。
- 缺点:反应较慢(通常需要等待一个 RTO 时间,RTO 往往 ≥ 200ms),效率低。
快速重传 —— 更积极的检测
为了解决超时重传的长时间等待问题,TCP 引入了快速重传。
- 原理:
- 接收方收到乱序的数据包时(比如收到了 5,但期望收到 3),会立即发送一个重复的 ACK(Dup ACK),ACK 号仍然是它所期望的下一个序列号。
- 发送方收到连续的三个重复的 ACK(即总共收到 4 个相同的 ACK,包括第一个正常的 ACK),就推断出该序列号对应的数据包已经丢失,而无需等待超时。
- 为什么是 3 次:1 或 2 次 Dup ACK 可能只是数据包乱序造成的“错误信号”,3 次是一个经验值,可以较好地平衡丢包误判和检测延迟。
- 优点:比超时重传快得多(通常在一个 RTT 内就能完成检测)。
- 缺点:依赖“连续” ACK,如果丢失的是窗口末尾的最后一个包或多个包,可能无法触发快速重传。
Forward ACK (FACK) —— 更精细的检测
FACK 是 Linux 内核采用的一种丢包检测算法,它利用 ACK 中的信息来更精确地定位丢失的包。
- 原理:
- 发送方维护两个关键变量:SND.NXT(待发送的下一个字节)和 SND.UNA(已确认的下一个字节)。
- 当收到一个 ACK 时,比较其 ACK 号与 SND.NXT,ACK 号小于 SND.NXT,说明有数据段未被确认。
- FACK 跟踪接收方已收到的最高序列号,通过计算已发送但未确认的字节数来判断丢包,当连续收到一定数量的重复 ACK 时,它就能更早地触发重传。
- 优点:在拥塞窗口较小或丢包模式复杂时,比标准的快速重传更敏锐、更准确。
Selective ACK (SACK)—— 高效处理连续丢包
标准 TCP 的 ACK 只能告知“期待的下一个序列号”,无法告诉发送方哪些包已经成功收到了,SACK 选项改变了这一点。
- 原理:
- TCP 选项字段中包含了 SACK 块,可以报告 1-4 个不连续的已经收到的数据块(收到 3-5 和 7-9,但缺失 6)。
- 发送方收到一个 Dup ACK(包含 SACK 信息)时,就能清楚知道哪些包已经到达(如 5 和 7 已到,但 6 丢失),从而仅重传丢失的包。
- 与快速重传的结合:发送方在收到 3 个 Dup ACK 并触发快速重传时,SACK 信息会告诉它要重传具体哪个包(比如包 6),而不是像标准 TCP 那样可能重传所有的未确认包。
- 优点:极大地提高了丢包重传效率,尤其在多个连续丢包时(如窗口中有 5 个包丢失,标准 TCP 可能需要多次 RTT 才能恢复,而 SACK 可以一次重组所有丢失的包)。
- 缺点:需要双方支持。
时间戳选项 —— 更精确的 RTT/RTO 计算
TCP 时间戳选项(RFC 1323)虽然不直接检测丢包,但为其他机制提供了基础。
- 原理:
- 每个数据包都携带一个时间戳。
- 接收方的 ACK 会回显这个时间戳。
- 发送方可以精确测量每个数据包的 RTT(而不是取平均),从而更准确地计算 RTO 值,避免不必要的超时。
- 意义:一个更准确的 RTO 可以减少“假超时”(即因为 RTO 设置过长而延迟丢包检测),也减少了“假重传”(RTO 过小导致误判)。
总结与对比
| 检测方式 | 触发条件 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 超时重传 | 重传计时器(RTO)到期 | 简单可靠,覆盖所有丢包 | 延迟高(RTO ~ 200ms+) | 所有丢失的兜底方案 |
| 快速重传 | 收到 3 个重复 ACK | 比超时快得多(~1 RTT) | 对单包丢失不敏感(依赖连续 ACK) | 单包或少量连续丢包 |
| FACK | 基于 ACK 号的精确窗口计算 | 更早、更准确地识别丢失 | 计算较复杂,依赖实现 | Linux 内核中性能较好 |
| SACK | 3 个 Dup ACK + SACK 信息 | 精确知道哪些包丢失,高效多包恢复 | 需要双方支持 | 高带宽、多丢包的场景 |
实际开发或排查中如何观察丢包?
- 系统层面(Linux):
netstat -s | grep -i "retrans":查看重传次数。ss -i:查看每个 TCP 连接的重传次数和 RTT。tcpdump:抓包后,观察重复 ACK 的数量和重传的数据包。
- 应用层面:
- 看到
TCP RTO或TCP Dup ACK的日志。 - 应用层观察到较高的延迟或连接超时。
- 看到
TCP 的丢包检测不是单一机制,而是多层级自适应系统:
- 首选:快速重传(基于 3 个 Dup ACK)+ SACK 精确定位,这是最快速、最经济的检测方式。
- 兜底:超时重传(基于 RTO),当快速重传失效(如尾部丢包、全局丢包)时,这是最后的保障。
- 协作:时间戳选项和 FACK 等机制,让 RTO 计算更准确,让检测更早发生。
理解这些机制,有助于你分析网络性能瓶颈(比如看到大量重传意味着链路质量差或拥塞),以及优化应用层代码(比如调整 Nagle 算法、窗口大小等)。
标签: TCP
版权声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。