TCP/IP 协议——十四章:TCP超时与重传

由于下层网络层(IP)可能出现丢失、重复或失序包的情况,TCP 协议提供可靠数据传输服务。为保证数据传输的正确性,TCP 重传其认为已经丢失的包。TCP 有两套重传机制,一是基于定时器(超时),二是基于确认信息的构成(快速重传)。

基于计时器的重传

TCP在发送数据时会设置一个计时器,若至计时器超时仍未收到数据确认信息(ACK),则会引发相应的超时或基于计时器的重传操作,计时器超时称为重传超时(Retansmission Timeouts,RTO)。

图中黑色那条就是因为定时器超时仍没有收到 ACK,所以引起了发送方超时重传。
实际上, TCP 有两个阈值来决定如何重传同一个报文段:一是愿意重传的次数 R1、二是应该放弃当前连接的时机 R2。R1 和 R2 的值应分别至少为 3 次和 100 秒,如果超过任何一个但还没能重传成功,会放弃该连接。当然这两个值是可以设置的,在不同系统里默认值也不同。
 
那么如何设定一个合适的超时的值呢?假设 TCP 工作在静态环境中,这很容易,但真实网络环境不断变化,需要根据当前状态来设定合适的值。

1、设置重传超时(RTO)

RTO(retransmission timeout)一般是根据RTT(round trip time)也就是往返时间来设置的。
若 RTO 小于 RTT,则会造成很多不必要的重传;
若 RTO 远大于 RTT,则会降低整体网络利用率,RTO 是保证 TCP 性能的关键。并且不同连接的RTT不相同,同一个连接不同时间的 RTT 也不相同,所以 RTO 的设置一直都是研究热点。

凭我们的直觉,RTO 应该比 RTT 稍大:

RTO=RTT+Δt

那么,RTT 怎么算呢:

SRTT=α(SRTT)+(1-α)RTTnew

SRTT(smooth RTT),RTTnew 是新测量的值。如上,为了防止 RTT 抖动太大,给了一个权值 a ,也叫平滑因子。a 的值建议在 80%~90%。举个例子,当前 SRTT=200ms,最新一次测量的 RTTnew=800ms,那么更新后的 SRTT=200×0.875+800×0.125=275ms.

根据前面求的SRTT计算出RTO:

RTO = min(ubound, max(lbound, (SRTT)β))

β是时延离散因子,推荐值1.3~2.0。 ubound是RTO上边界,lbound是下边界。这种计算方法就是经典方法。它是的RTO值设置为1s或约两倍的SRTT。

这种方法缺点就是没法适应大规模的变动(网络不稳定情况)。

2、退避指数

根据前面的公式,我们可以得到 RTO。一旦超过 RTO 还没收到 ACK,就会引起发送方重传。但如果重传后还是没有在 RTO 时间内收到 ACK,这时候会认为是网络拥堵,会引发 TCP 拥塞控制行为,使 RTO 翻倍。则第 n 次重传的 RTOn 值为:

RTOn=2^(n−1)×RTO1

下图是一个例子:

3、带时间戳的 RTT 测量

前面说了 RTO 的公式,它和 RTT 有关,那么每一次的 RTT 是如何得到的呢?

在之前 TCP 连接管理的时候讲过,TCP有一个 TSOPT (timestamp option) 选项,它包含两个时间戳值。它允许发送者在报文中带上一个32比特的时间戳值(TSV),然后接收方将收到的值原封不动的填入 ACK 报文段中 TSOPT 选项的第二部分,时间戳回显字段(TSER)。发送方收到 ACK 以后,将当前时间戳减去 TSOPT 选项的 TSER 就可得到精确的RTT值。

但是这里有很微妙的细节:接收方在收到数据包后,并不是立即发送 ACK,通常会延时“一小会儿”,多等待几个数据包后返回一个累积 ACK。此时接收方将确认时间最近的报文段的 TSV 填入 TSER 发送给发送方。

4、重传二义性与 Karn 算法

还有另一个重要的细节,如果测量 RTT 的样本出现了超时重传,导致我们收到 ACK 时无法分辨是对哪一次的确认,这时候 RTT 的值可能是不正确的。

因此,Karn 算法规定:此时不更新 RTTnew 的值。并且如果发生再次重传,则采用退避后的 RTO 的值,直到发送成功,退避指数重新设定为 1 。

 

基于确认信息的重传(快速重传)

在大多数情况下,计时器超时并触发重传是不必要的,也不是期望的,因为 RTO 通常是大于 RTT(约2倍或更大),因此基于计时器的重传会导致网络利用率降低。

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

首先我们要知道,接收方收到失序报文段时,应立即生成确认信息(重复 ACK),以便发送方尽快、高效地填补空缺。而发送方在收到重复 ACK 时,无法判断是由于数据包丢失还是仅仅因为延迟,所以发送方等待一定数目的重复 ACK (重复 ACK 阈值,dupthresh),这时可以认为是数据包丢失,即便还未超时,也立即发送丢失的分组。
 
所以快速重传概括如下:TCP 发送方在观测到至少 dupthresh ( 通常是 3 ) 个重复 ACK,立即重传,而不必得到计时器超时。当然也可以同时发送新的数据。

如下图所示:

 

1、带选择确认的重传

 TCP发送段的任务是通过重传丢失的数据来填补接收端缓存中的空缺,但同时也要尽可能保证不重传已正确接收到的数据。在很多环境下,合理采用SACK(Selective Acknowledgment)信息能更快地实现空缺填补,且能减少不必要的重传,原因在于其在一个RTT内获知多个空缺(最多3个)。

2、接收端的 SACK 行为

接收端在 TCP 连接建立期间收到 SACK 选项即可生成 SACK。通常来说,当收到失序报文段,接收方就会生成 SACK。

第一个 SACK 块包含的应该是最近收到的(most recently received)报文段的序列号范围。由于 SACK 选项空间有限,应尽可能向发送方提供最新信息。其余的 SACK 按先后顺序依次排列,也就是说,该 ACK 报文段除了包含最新接收的序列号信息,还应重复之前的 SACK 信息。这是因为 ACK 报文段是没有重发机制的,可能会丢失,重复提高了其鲁棒性。

3、发送端的 SACK 行为

发送方应该充分利用 SACK 信息来进行重传,称为选择性重传。发送方记录累积 ACK 信息和 SACK 信息,当接收到相应序列号范围内的 ACK 时,在其重传缓存中标记该报文段重传成功。

伪超时与重传

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

 

posted @ 2019-04-09 17:31  wang-shishuang  阅读(1489)  评论(1编辑  收藏  举报