网络3️⃣TCP-可靠性-重传机制

TCP 实现可靠传输,离不开序列号与确认应答

  • SEQ:Sequence Number
  • ACK:Positive Acknowledgement
  • 当发送端的数据到达接收方主机时,会返回一个确认应答消息,代表已收到消息。
  • 如果数据包在传输过程中丢失,TCP 会采用重传机制
    • 超时重传
    • 快速重传
    • SACK
    • D-SACK

1、超时重传

1.1、超时重传

Timeout Retransmission:发送数据时设定一个定时器

超过指定时间未收到对方的 ACK 报文,就会重发该数据

发生超时重传的场景

  • 数据包丢失:对方根本没收到数据包,更不可能发送 ACK。

  • 确认应答丢失:对方发送的 ACK 丢失。

    超时重传的两种情况

1.2、相关概念

1.2.1、往返时延 RTT

往返时延Round-Trip Time):数据发送时刻到接收到确认时刻的差值。

i.e. 包的往返时间

RTT

1.2.2、重传超时 RTO

重传超时Retransmission Timeout):即超时重传时间

精确测量 RTO 值是非常重要的,可以使得重传机制更高效。

  • RTO 过大:重发慢,丢包很久才重发。👉效率低,性能差

  • RTO 过小:重传快,还没丢就重发。👉增加网络拥堵,导致更多超时和重发

    超时时间较长与较短

HintRTO 值应略大于 RTT 值

RTT 值经常变化,因此 RTO 是一个动态变化的值

RTO 应略大于 RTT

1.3、RTO 计算

Linux 中计算 RTO 的步骤

  1. 采样 RTT:TCP 采样 RTT 并进行加权平均,计算出一个平滑的、动态变化的 RTT 值。
  2. 采样 RTT 偏差(aka. 抖动):即 RTT 波动范围,避免 RTT 出现较大波动。

RFC6289 建议的 RTO 计算公式

  • SRTT:计算的平滑的 RTT 值。
  • DevRTR:SRTT 与最新 RTT 的差值。
  • 根据大量实验结果,Linux 中 α = 0.125,β = 0.25, μ = 1,∂ = 4

  • 超时重发时,会将下一次超时时间间隔设置为之前的 2 倍(避免在网络环境差的情况下频繁重发)。

    RFC6289 建议的 RTO 计算

1.3、不足

超时重传的不足超时周期相对较长

👇 快速重传机制,可解决超时重发的时间等待。

2、快速重传

快速重传(Fast Retransmit):不以时间为驱动,而是以数据驱动重传。

连续收到三个相同的 ACK 报文时重传丢失的报文段

(此时还未到超时重传定时器的过期时间,因此效率更高)

2.1、工作流程

示例:发送方先后发出 5 份数据,但 Seq2 丢失。

  • Seq1:接收方收到 Seq1,回复 ACK2(代表下一个期望收到的报文 Seq=2)

  • Seq2:丢失

  • Seq3:接收方收到 Seq3,检查 Seq 不是期望收到的 2,仍回复 ACK2。

  • Seq4、Seq5:同理,接收方会回复 ACK2。

  • 发送方收到 3 个相同的 ACK 报文(ACK2),重传 Seq2。

    快速重传机制

2.2、不足

快速重传解决了超时时间过长的问题,但仍存在问题。

无法明确重传哪些报文

示例:发送方先后发出 5 份数据,但 Seq2 和 Seq3 丢失。

  • Seq1:接收方回复 ACK2(代表下一个期望收到的报文 Seq=2)。
  • Seq2 和 Seq3:丢失
  • Seq4 和 Seq5:接收方检查 Seq 不是期望收到的 2,先后回复两次 ACK2。

重传哪些报文

  • 仅 Seq2效率低。因为 Seq3 还需要经历 3 次重复的 ACK 才能触发重传。
  • Seq2 后的所有资源浪费。Seq4 和 Seq5 重复发送了。

👇 SACK 方法,可以选择性重传。

3、SACK

选择性确认(Selective Acknowledgment)

在 TCP 首部的选项字段里添加 SACK

3.1、SACK 方法

SACK 方法:使用 SACK 告知发送方已接收的数据

  • 发送方触发快速重传时,根据接收方的 SACK 信息来重传丢失的数据
  • 在 Linux 中通过 net.ipv4.tcp_sack 控制(Linux 2.4 后默认开启)。

示例

  • 发送方收到了三次同样的 ACK 报文(ACK200),触发快速重发机制。

  • 通过 SACK 信息发现 200~299 数据丢失,则重发此 TCP 段。

    选择性确认

3.2、D-SACK

Duplicate SACK:使用 SACK 告知发送方重复接收的数据

  • 发送方触发超时重传时,根据接收方的 SACK 信息来得知数据已被接收(没有丢失)
    • 可能是 ACK 丢失,而不是数据丢失。
    • 可能是数据遭遇网络延迟。
  • 在 Linux 中通过 net.ipv4.tcp_dsack 参数控制(Linux 2.4 后默认开启)。

① ACK 丢失

场景:接收方收到数据了,但是 ACK 报文丢失

  • 发送方:迟迟没有接收到 ACK 报文,触发超时重传(第一个数据包 3000~3499)。

  • 接收方:发现数据重复接收,回复一个包含 SACK 的 ACK 报文

    • SACK=3000~3500:代表重传的这一段数据已接收(这里的 SACK 就是 D-SACK)。
    • ACK=4000:代表 4000 之前的数据已被接收。
  • 发送方:得知数据没有丢失,是 ACK 丢失

    ACK 丢包

② 网络延迟

场景:发送方的某个包被网络延迟了,导致接收方没有发出相应的 ACK 报文。

(但其它包正常接收)

  • 500~999:正常接收,ACK1000。
  • 1000~1499:网络延迟,接收方不会 ACK。
  • 1500~1999, 2000~2499, 2500~2999
    • ACK1000:代表期望收到 seq1000 的数据。
    • SACK:代表已接收的数据(此处是 SACK 方法,标识已接收)。
  • 发送方:连续收到 3 个相同的 ACK 报文,触发快速重传(重传后的报文已被接收)。
  • 被延迟的数据(1000~1499):到达接收方,接收方回复一个包含 SACK 的 ACK 报文。
    • SACK=1000~1500:代表重传的这一段数据已接收(此处是 D-SACK,标识数据重复接收)。
    • ACK=3000:代表 3000 之前的数据已被接收。

网络延时

对比

  • SACK 方法:通过 SACK 得知哪些数据已经被接收,从而确定要重传的数据
  • D-SACK:通过 SACK 得知哪些数据已经被接收,从而得知数据已被接收(无需重传)
posted @ 2023-06-29 20:47  Jaywee  阅读(234)  评论(0编辑  收藏  举报

👇