TCP重传机制

  • Post author:
  • Post category:其他


由于TCP的下层网络(IP)可能出现丢失、重复或失序的情况,TCP协议提供可靠数据传输服务。为保证数据传输的正确性,TCP会重传其认为已丢失(包括报文中的比特错误)的包。TCP使用两套独立的机制来完成重传,一是基于时间,二是基于确认信息的构成。

第一种基于时间的重传在其下的数据链路层、网络层乃至同层的UDP协议都有使用,即设置一个计时器来判断数据传输是否超时,当然它们对于计时器时间的设定规则有所不同。本文主要聚焦于TCP的第二种重传机制。

快速重传

快速重传机制[RFC5681]基于接收端的反馈信息来引发重传,而非基于计时器超时重传。与超时重传相比,快速重传能更加及时有效地修复丢包情况。

快速重传机制要求当接收到失序报文段时,TCP需要立即生成确认信息(重复ACK),并且失序情况表明在后续数据到达前出现了丢包,发送端的工作即为尽快填补丢包带来的数据段空缺。

所谓重复ACK,举个例子,假设A与B之间建立连接,A向B发送数据,有4个TCP报文段,序列号分别为:N-1,N,N+1,N+2。再假设序列号N的报文段丢失(也许只是延迟到达),将会导致失序:N-1,N+1,N+2。此时接收端回复的ACK将会是N,N,N(接收到N-1的报文段后接收端认为下一个应该是N)。因此TCP等待一定数目的重复ACK(称为重复ACK阙值或dupthresh),来决定数据是否丢失并触发快速重传。通常这个阙值为常量3,但也有一些协议实现可基于当前的失序程度动态调节该值。

快速重传算法可以概括如下:TCP发送端在观测到至少dupthresh个重复ACK后,即重传可能丢失的数据分组,而不必等到重传计时器超时。不采用SACK时,在接收到有效ACK前最多只能重传一个报文段。根据重复ACK推断的丢包通常与网络拥塞有关,因此快速重传也会触发拥塞控制机制。采用SACK(见下文),ACK可包含额外信息,使得发送端在每个RTT时间内可以填补多个空缺。

SACK

由于TCP采用累积ACK确认,因此TCP有时候并不能正确地确认之前已经接收的数据。由于接收的数据是无序的,所以接收到的数据的序列号也是不连续的。在这种情况下,TCP接收方的数据队列中会出现空洞的情况。因此在提供字节流传输服务时,TCP接收方需要防止应用程序使用超出空间的数据。一种方法是直接禁止交付存在空洞的数据,直到空洞被填补。而另一种方法则是使用SACK选项。

如果TCP发送方能够了解接收方当前的空洞(以及序列空间中超出空洞的乱序数据块),它就能在报文段丢失或接收方遗漏时更好地进行重传工作。接收方通过SACK选项能够提供确认信息描述乱序数据,以帮助发送方有效地利用信息进行重传。

SACK信息保存于SACK选项中,包含了接收方已经接收的数据块的序列号范围,每个范围被称作一个SACK块,由一对32位的序列号表示。因此,一个SACK选项包含了n个SACK块,长度为(8n+2)个字节,增加的2个字节用于保存SACK选项的种类与长度。由于TCP头部选项的空间有限,因此一个报文段中发送的最大的SACK块数目为3(假设使用了时间戳选项)。虽然只用SYN报文段才能包含“选择确认”选项,但是只要发送方已经发送了该选项,SACK块就能通过任何报文段发送出去。

带选择确认的重传

合理采用SACK信息能更快地填补数据空洞,且能减少不必要的重传,原因在于一个RTT内能获知多个空缺。当采用SACK时,一个ACK可包含3个告知失序数据的SACK信息,每个SACK信息包含32位的序列号,代表接收端存储的失序数据的起始至最后一个序列号(加1)。

伪超时与重传

在很多情况下,即使没有出现数据丢失也可能引发重传。这种不必要的重传称为伪重传(spurious retransmission),造成伪重传的主要原因是伪超时(spurious timeout),即过早判定超时,其他因素如包失序、包重复,或ACK丢失也可能导致该现象。在实际RTT显著增长以致超过了当前RTO时,就可能出现伪超时。

包失序

在IP网络中出现包失序的原因在于IP层不能保证包传输是有序进行的,但这种策略是有利的,因为IP可以选择不同的传输链路,合理利用现有链路。还有其他的原因,例如一些高性能路由器会采用多个并行数据链路进行分组转发,以及不同的处理延时也会导致包的离开顺序与到达顺序不匹配。

当传输出现失序时,TCP可能会在某些方面受到影响。如果失序发生在反向(ACK)链路,就会使得TCP发送端窗口快速前移,接着又可能会收到一些显然重复而应被丢弃的ACK。由于TCP的拥塞控制行为,这种情况会导致发送端出现不必要的流量突发(即瞬时的高速发送)现象,影响可用网络带宽。

如果失序发生在正向链路,TCP可能无法正确识别失序和丢包——数据的丢失和失序都会导致接收端收到无序的包,造成数据空缺。当失序程度不是很大时(如两个相邻的包交换顺序),这种情况可以迅速得到处理。反之,当出现严重失序时,TCP会误认为数据已经丢失,这就会导致伪重传。对此问题,可以设置一个合适的快速重传触发阙值来一定程度解决这一个问题。

包重复

IP协议可能出现将单个包传输多次的情况。例如,当链路层网络协议执行一次重传,并生成同一个包的两个副本。包的多次重复会使接收端生成一系列的重复ACK,这足以触发伪快速重传。使用SACK(特别是DSACK)就可以简单地忽略这个问题。

本文内容摘自《TCP/IP详解 卷1:协议(中文版)第2版》,有改动



版权声明:本文为qq_37653144原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。