TCP重传

2025年3月17日 | 阅读 7 分钟

TCP 重传是指重新在网络上发送那些已经丢失或损坏的数据包。在这里,重传是像 TCP 这样的协议用来提供可靠通信的机制。可靠通信意味着协议保证数据包的送达,即使数据包已经丢失或损坏。

网络是不可靠的,不保证延迟或丢失/损坏数据包的重传。使用确认和对损坏或丢失数据包进行重传的组合的网络提供了可靠性。

重传机制

在这里,重传意味着数据包丢失,导致缺少确认。缺少确认会触发计时器超时,从而导致数据包重传。在这里,计时器意味着如果在计时器到期前未收到确认,则数据包将被重传。

让我们考虑以下重传场景。

场景 1:当数据包丢失或出错时。

TCP Retransmission

在此场景中,数据包已发送到接收方,但在超时期间内未收到任何确认。当超时期间到期时,数据包将再次重新发送。当数据包被重传后,会收到确认。一旦收到确认,将不再发生重传。

场景 2:当数据包收到但确认丢失时。

TCP Retransmission

在此场景中,数据包已在另一端收到,但确认丢失,即发送方未收到 ACK。一旦超时期间到期,数据包将被重新发送。在另一端有两个数据包副本;即使数据包已正确收到,但未收到确认,因此发送方会重新发送数据包。在这种情况下,重传本可以避免,但由于 ACK 丢失,数据包被重传。

场景 3:当发生早期超时时。

TCP Retransmission

在此场景中,数据包已发送,但由于确认延迟或在实际超时发生之前发生了超时,数据包被重传。在这种情况下,由于确认延迟或超时设置早于实际超时,数据包被不必要地再次发送。

在上述场景中,第一个场景无法避免,但其他两个场景可以避免。让我们看看如何避免这些情况。

发送方应等待多久?

发送方为 ACK 设置超时周期。超时周期可以有两种类型:

  • 过短:如果超时周期过短,重传将是浪费的。
  • 过长:如果超时周期过长,当数据包丢失时会导致过度延迟。

为了克服以上两种情况,TCP 将超时设置为 RTT(往返时间)的函数,往返时间是指数据包从源传输到目的地然后再返回所需的时间。

如何获得 RTT?

RTT 可能因网络特性而异,也就是说,如果网络拥塞,则意味着 RTT 非常高。我们可以通过观察 ACK 来估算 RTT。

让我们看看如何测量 RTT。

我们将使用原始算法来测量 RTT。

步骤 1:首先,我们测量每个段或 ACK 对的SampleRTT。当发送方发送数据包时,我们知道发送数据包的计时器,并且我们也知道收到确认的计时器。计算这两个时间之间的差值,这就是SampleRTT

步骤 2:我们不会只取一个样本。我们将继续获取不同的样本并计算这些样本的加权平均值,这将成为 EstRTT(估计 RTT)。

其中,α+ β = 1

α 介于 0.8 和 0.9 之间

β 介于 0.1 和 0.2 之间

步骤 3:根据 EstRTT 设置超时。

timeout = 2 * EstRTT。

超时时间设置为估计 RTT 的两倍。这就是实际超时因子的计算方法。

该方法中的一个缺陷

原始算法存在一个缺陷。让我们考虑两种情况。

场景 1。

TCP Retransmission

上图显示发送方发送了数据,这被认为是原始传输。在超时期间内未收到确认。因此,发送方重新传输数据。重新传输数据后,会收到确认。假设收到的是原始传输的确认,那么SampleRTT是在原始传输时间和收到确认时间之间计算的。但实际上,SampleRTT应该是在重传时间和收到确认时间之间计算的。

场景 2。

TCP Retransmission

上图显示发送方发送了原始数据包,我们也收到了该数据包的确认。但是确认是在重传数据后收到的。如果我们假设确认属于重传,那么SampleRTT是在重传时间和收到确认时间之间计算的。

在以上两种情况中,都存在一个歧义,即不知道确认是针对原始传输还是针对重传。

上述算法的结论。

  • 在这里,ACK 并不表示确认传输,而是表示确认收到数据。
  • 如果考虑第一种情况,重传是针对丢失的数据包进行的。在这种情况下,我们假设 ACK 属于原始传输,因此 SampleRTT 变得非常大。
  • 如果考虑第二种情况,发送了两个相同的数据包,因此发生了重复。在这种情况下,我们假设 ACK 属于重传,因此 SampleRTT 变得非常小。

为了克服上述问题,Karn/Partridge 算法提供了一个简单的解决方案。该算法提供了一个简单的解决方案,它收集一次发送的样本,并且在计算估计 RTT 时不考虑重传时间的样本。

Karn/Partridge 算法

在上述两种情况下,都会发生重传,并且我们考虑了 Sample RTT。但是该算法在重传时不会考虑 Sample RTT。由于发生了重传,这意味着在此往返时间内发生了某些事情,或者网络中可能发生了一些拥塞。为了克服这个问题,该算法在每次重传后将超时加倍。该算法在 TCP 网络中实现。

局限性

它不考虑 RTT 的方差。

  • 如果方差小,EstimatedRTT 会很准确。如果方差大,EstimatedRTT 就不准确。

为了克服上述限制,开发了 Jacobson/Karels 算法,该算法将方差因子引入 RTT。

Jacobson/Karels 算法

该算法的开发是为了克服Karn/Partridge算法的限制。它计算 SampleRTT 和 EstimatedRTT 之间的差值,并根据差值来增强 RTT。

平均 RTT 的计算

  • 首先,我们计算差值因子。

Diff = SampleRTT - EstimatedRTT

  • 现在,我们计算 EstimatedRTT,其计算方式与我们上面做的一样。

EstRTT = EstRTT + (δ*Diff)

  • 现在,我们计算差值因子的平均值。

Dev = Dev + δ ( |Diff| - Dev)

这里,Dev 是偏差因子,δ 是介于 0 和 1 之间的因子。Dev 是从EstRTT测得的方差估计。

  • 我们在计算超时值时将考虑方差。
Timeout = µ * EstRTT + ɸ * Dev

其中,µ =1 且 ɸ =4

快速重传

基于超时的重传策略效率低下。TCP 是一种滑动窗口协议,因此每当发生重传时,它都会从丢失的数据包开始发送。

TCP Retransmission

假设我传输了数据包 0、1、2 和 3。由于接收方已收到数据包 0 和 1,数据包 2 在网络中丢失。我已经收到了数据包 0 和 1 的确认,因此我发送了另外两个数据包,即数据包 4 和 5。当发送数据包 3、4 和 5 时,由于 TCP 确认是累计的,因此它会确认它按顺序收到的数据包。我在超时期间内未收到数据包 2、3、4 和 5 的确认,因此我重新传输了数据包 2、3、4 和 5。由于数据包 2 丢失,但其他数据包,即 3、4、5 已在另一端收到,但由于这种超时机制,它们仍被重传。

如何消除这种超时效率低下的问题?

滑动窗口下的更好解决方案

假设 n 数据包已丢失,但仍收到 n+1、n+2 及后续数据包。接收方不断收到数据包并发送 ACK 数据包,表示接收方仍在等待第 n 个数据包。接收方正在发送重复的或重复的确认。在上述情况下,由于数据包 2 已丢失,数据包 1 的 ACK 发送了三次。这个重复的 ACK 数据包表明第 n 个数据包丢失了,但后续数据包已收到。

上述情况可以通过以下方式解决:

  • 发送方可以将“重复 ACK”视为一个早期提示,表明第 n 个数据包已丢失,因此发送方可以尽快进行重传,即发送方不应等到超时发生。
  • 发送方可以在 TCP 中实现快速传输策略。在快速传输策略中,发送方应将三重重复 ACK 视为一个触发器并进行重传。

TCP 使用三个重复 ACK 作为触发器,然后执行重传。在上述情况下,当收到数据包 1 的三个 ACK 时,发送方应发送丢失的数据包,即数据包 2,而不必等待超时发生。


下一主题CAN 协议