tcp重传机制
TCP 的可靠性,很大程度上依赖于其精妙的重传机制。当数据包在网络中丢失或乱序时,TCP 能够自动发现并重新发送,确保数据最终能够完整、有序地到达目的地。
这套机制主要由两个核心部分组成:超时重传和快速重传。
超时重传 (Timeout Retransmission)
这是 TCP 重传机制的"兜底方案",也是最基础的保障。它的核心思想很简单:发送方为每一个发出的数据包启动一个计时器,如果在规定时间内没有收到接收方的确认(ACK),就认为数据包已经丢失,并重新发送。
核心:动态计算超时时间 (RTO)
超时重传的关键在于如何设置这个"规定时间",即重传超时时间 (RTO, Retransmission Timeout)。
- RTO 太短:会导致不必要的重传,浪费网络带宽,加剧网络拥塞。
- RTO 太长:在真正丢包时,应用程序会因等待过久而感知到明显的延迟。
因此,TCP 不会使用一个固定的 RTO 值,而是根据网络的实时状况动态计算。它通过测量数据包发出到收到确认的时间,即往返时间 (RTT, Round-Trip Time),来估算 RTO。
为了应对网络抖动,TCP 采用了一套平滑算法来更准确地预测 RTO:
- 平滑往返时间 (SRTT):对多次测量的 RTT 样本进行加权平均,得到一个相对稳定的 RTT 值。
- 往返时间变化量 (RTTVAR):用来衡量 RTT 的波动程度。网络越不稳定,这个值越大。
最终,RTO 的计算公式(遵循 RFC 6298 标准)为:
RTO = SRTT + 4 * RTTVAR这个公式确保了 RTO 值通常会比平均 RTT 长,以容纳正常的网络延迟波动,避免误判。
优化:指数退避 (Exponential Backoff)
当发生超时重传后,如果网络依然拥塞,连续的重传可能会加重问题。为此,TCP 采用了指数退避策略:
- 每次重传后,下一次的 RTO 时间会翻倍(例如,第一次 RTO 是 1 秒,第二次就是 2 秒,第三次是 4 秒)。
- 这种策略可以有效减轻网络负载,给网络一个"喘息"的机会。如果重传次数超过上限(例如 5 次),TCP 会认为网络出现了严重故障,并关闭连接。
快速重传 (Fast Retransmit)
超时重传虽然可靠,但有时等待时间过长。为了提升效率,TCP 引入了快速重传机制作为优化。它不依赖计时器,而是通过接收方的反馈来立即发现丢包。
触发条件:3 个重复 ACK
快速重传的触发依赖于一个关键信号:收到 3 个重复的 ACK。
工作流程如下:
- 假设发送方按顺序发送了数据包 P1, P2, P3, P4, P5。
- 接收方收到了 P1,回复
ACK=2(期望收到 P2)。- P2 在网络中丢失了。
- 接收方收到了 P3,发现顺序不对(它还在等 P2),于是它不能确认 P3,只能再次回复
ACK=2,告诉发送方"我还在等 P2"。- 接着,接收方又收到了 P4 和 P5,它们同样会触发回复
ACK=2。- 当发送方连续收到 3 个 针对 P2 的重复 ACK(即总共收到 4 个
ACK=2)时,它就不再等待 RTO 计时器超时,而是立即重传丢失的数据包 P2。这种机制大大缩短了丢包恢复的时间,通常能在大约一个 RTT 内完成重传,而不是等待可能长达数秒的 RTO。
高级优化:选择性确认 (SACK)
SACK(Selective Acknowledgment,选择性确认)选项是TCP协议的一项扩展,旨在解决传统TCP在数据包丢失时重传效率低下的问题。它允许接收方精确地告知发送方哪些数据已经成功接收,即使这些数据不是按顺序到达的,从而避免了不必要的重传。
传统TCP确认机制的局限
为了理解SACK的价值,我们先看一个传统TCP确认机制(累积确认)的例子:
- 发送数据 :假设发送方连续发送了数据包
1, 2, 3, 4, 5, 6。- 发生丢包 :数据包
3在网络中丢失,但1, 2, 4, 5, 6都成功到达了接收方。- 接收方反馈 :接收方收到了乱序的数据包
4, 5, 6,但由于它只能进行"累积确认",即只能确认到最后一个按序到达的数据,所以它只能向发送方回复ACK=2,意思是"我已收到2及之前的所有数据,现在期待收到3"。- 发送方行为 :发送方收到
ACK=2后,会认为从数据包3开始的所有后续数据(3, 4, 5, 6)都已丢失,即使4, 5, 6已经安全抵达。因此,它会重传3, 4, 5, 6这四个数据包。这个过程造成了带宽的浪费,因为数据包
4, 5, 6被重复发送了。SACK选项的工作原理
SACK通过引入"选择性确认"解决了上述问题。它的工作流程分为两个阶段:
1. 能力协商阶段
在TCP连接建立的三次握手阶段,通信双方会协商是否支持SACK功能。
- 客户端在发送的第一个
SYN包中,会带上一个SACK-permitted的TCP选项。- 服务器如果在
SYN-ACK响应中也带上SACK-permitted选项,就表示双方都支持SACK,后续传输中就可以使用该功能。2. 数据传输阶段
当连接中发生丢包时,SACK机制就会发挥作用:
- 发送数据 :同样,发送方发送了数据包
1, 2, 3, 4, 5, 6。- 发生丢包 :数据包
3丢失,1, 2, 4, 5, 6到达接收方。- 接收方反馈 :接收方在回复
ACK=2(累积确认)的同时,会在TCP报文的选项字段中添加一个 SACK选项 。这个选项会明确指出已经收到的非连续数据块,例如SACK [4-6],表示"虽然我在等3,但我已经把4到6号数据都收到了,请帮我记下来"。- 发送方行为 :发送方解析SACK选项后,就能精确地知道只有数据包
3丢失了。因此,它只需要重传数据包3,而不会再浪费资源重传已经成功送达的4, 5, 6。SACK的优势
通过这种方式,SACK带来了显著的性能提升,尤其是在高丢包率的网络环境(如无线网络)中:
- 减少冗余重传:只重传真正丢失的数据包,极大地节省了网络带宽。
- 提升传输效率:避免了因单个丢包导致整个传输窗口停滞,保持了较高的吞吐量。
- 降低传输延迟:发送方能更快地识别并修复丢包,减少了等待超时重传的时间。
D-SACK
如果说 SACK 是为了"精准重传",那么 D-SACK (Duplicate SACK) 就是为了"精准诊断"。
D-SACK 是 SACK 的一项扩展(定义于 RFC 2883),它的主要作用不是告诉发送方"我缺什么",而是告诉发送方**"我收到了重复的数据"**。这听起来可能像是一个微不足道的细节,但它能让发送方极其聪明地推断出网络到底发生了什么故障,从而避免不必要的性能下降。
在普通的 SACK 机制中,SACK 块告诉发送方哪些数据已收到但未按序到达。而在 D-SACK 中,接收方利用 SACK 选项的第一个块来报告重复接收的数据段。
判定规则(接收方):
接收方通过以下两种方式之一来标记 D-SACK:
- 起始序号小于确认号 (ACK Number): 如果第一个 SACK 块的起始序号小于 ACK 字段中的序号,说明这个块包含的数据已经被累积确认过了,是重复的。
- 包含在第二个 SACK 块中: 如果第一个 SACK 块的范围完全被第二个 SACK 块覆盖,也说明它是重复的。
工作流程示例:
- 发送 :发送方发送数据包
Seq 1000-1499。- 丢包/延迟 :接收方没收到
1000-1499,但收到了后续的1500-1999、2000-2499。接收方回复ACK 1000并带上 SACK1500-2500。- 触发重传 :发送方收到 3 个重复的
ACK 1000,触发快速重传 ,重新发送Seq 1000-1499。- 意外到达 :就在重传的同时,原本那个"迟到"的原始包
Seq 1000-1499终于到达了接收方。- D-SACK 响应 :接收方此时收到了两份
1000-1499。它会回复ACK 2500(表示数据已补齐),并在 SACK 选项中放入 D-SACK1000-1500,明确告诉发送方:"你刚才重传的那个包,我其实早就收到了,这是重复的。"D-SACK 的核心价值:网络故障诊断
D-SACK 最大的意义在于它赋予了发送方区分网络故障类型的能力。通过收到 D-SACK,发送方可以做出更明智的决策,而不是盲目地降低传输速度。
1. 区分"丢包"与"乱序/延迟"
- 场景:发送方触发了快速重传。
- 无 D-SACK :发送方假设包丢了,认为网络拥塞,于是减小拥塞窗口 (cwnd),降低发送速度。
- 有 D-SACK :发送方意识到包没丢,只是乱序了。它会认为网络并没有拥塞,因此不减小(或撤销减小)拥塞窗口,保持高速传输。
2. 区分"数据包丢失"与"ACK 丢失"
- 场景:接收方收到了所有数据,但 ACK 应答包在路上丢了。发送方超时重传。
- D-SACK 反馈:接收方收到重传包后,回复 D-SACK。
- 结果:发送方得知数据没丢,是 ACK 丢了。这有助于发送方调整重传超时时间 (RTO),避免过于敏感的超时重传。
3. 检测数据包复制
- 如果网络中存在设备错误地复制了数据包,D-SACK 也能帮助发送方发现这一异常。
SACK 解决了"缺什么补什么"的问题,提升了传输效率;而 D-SACK 解决了"为什么补"的问题,提升了网络的健壮性和拥塞控制的准确性。它帮助发送方避免因为网络抖动(乱序)而误判为网络拥塞,从而维持了更高的吞吐量。
总结:
| 机制 | 核心作用 | 触发条件 | 优点 | 缺点 |
|---|---|---|---|---|
| 超时重传 | 兜底保障 | RTO 计时器超时 | 绝对可靠,应对严重网络问题 | 等待时间长,效率低 |
| 快速重传 | 加速恢复 | 收到 3 个重复 ACK | 减少等待,提升效率 | 无法处理多包丢失,可能误判 |
| SACK | 精准重传 | 快速重传 + SACK 选项 | 只重传丢失的包,效率极高 | 增加协议复杂度和开销 |
| D-SACK | 网络诊断 | 收到重复数据包 | 避免误判拥塞,优化流控 | 增加协议复杂性 |
这四种机制共同构成了一个智能、高效的 TCP 重传体系:
- 快速重传 优先于 超时重传 触发,以应对偶发丢包。
- SACK 在快速重传的基础上,让重传更加精准。
- D-SACK 则在重传发生后,帮助发送方进行"事后分析",优化未来的传输策略。
- 如果以上所有机制都失效(例如网络完全中断),最终的 超时重传 机制将作为最后的保障来恢复连接。