从上一篇示例中我们可以看到在TCP中有一个重要的过程就是决定何时进行超时重传,也就是RTO的计算更新。由于网络状况可能会受到路由变化、网络负载等因素的影响,因此RTO也必须跟随网络状况动态更新。如果TCP过早重传,则可能会向网络中注入很多重复报文,如果过晚重传,则在丢包时候则会影响滑窗前行可能会降低网络利用率。因为TCP在接收到数据后会发送累计的ACK number,因此TCP发送某个系列号的报文后,在接收到覆盖此系列号的ACK报文的时候,测量发送和接收之间的时间,这个测量就叫做RTT采样(RTT sample)。TCP对于每个连接都会根据RTT采样来维护跟新RTO,同时还会维护一个RTO超时的定时器。注意是对每个连接维护一个超时定时器,而不是对每个发出去的TCP报文。当TCP发出数据报文(或者SYN、FIN报文)的时候,如果之前没有等待ACK的报文则会设置这个连接的RTO定时器,如果之前有等待ACK的报文,则并不会重启RTO定时器。当TCP同时有多个报文发出且没有等到ACK的时候,则会先重传第一个报文,第一个报文重传成功收到ACK后,再设置RTO定时器然后重传第二个报文。

本篇先来介绍一下协议中更新计算RTO的方法。协议中主要有两种方法来计算RTO一种是RFC793的经典方法(classic method),另一种是RFC6298的标准方法(standard method)。

一、经典方法

在原始的RFC793中关于RTO更新的介绍只有半页文字的样子,它首先让TCP使用下面的公式更新一个平滑RTT估计(smoothed RTT estimator、简称SRTT):

  1. SRTT = ( ALPHA * SRTT ) + ((1-ALPHA) * RTT)

其中RTT是之前介绍的一个RTT采样值,ALPHA则是一个平滑因子(smoothing factor),协议给出的示例范围是0.8--0.9之间。这个过程也叫做指数加权移动平均(exponentially weighted moving average、简称EWMA)。可以看到这个计算过程只需要保留一个RTT采样值就行了,而不需要保留过多的历史RTT采样。

接着在按照下面公式计算出RTO:

  1. RTO = min[UBOUND,max[LBOUND,(BETA*SRTT)]]

其中BETA是一个延迟因子,协议给出的示例范围是1.3--2.0。UBOUND是一个RTO上限,LBOUND是一个RTO下限,UBOUND和LBOUND协议给出的示例范围分别是1分钟和1秒,显然这两个值对于现代TCP网络可能并不合适。

二、标准方法

RFC1122指出上面介绍的计算RTT的经典方法中存在两个问题,一个是在发生TCP重传的时候,RTT采样的精确测量非常困难,第二个问题是经典方法认为RTT是比较平稳的状态,变化比较小,因此SRTT的计算是不合适的。实际上比如在低速网络中,TCP的数据包的不同大小会导致不同的传输耗时,进而可能就会导致RTT采样值差距比较大。对于上面两个问题第一个问题由karn算法解决,karn算法我们后续进行介绍。第二个问题由Jacobson算法解决,该算法在RTO估计中添加了一个用于反映RTT波动的RTTVAR变量。而RFC6298就是一个基于Jacobson算法的RTO计算文档,我们把这种RTO计算方法称为标准方法。

1、RTO计算及更新

为了计算当前的RTO,TCP发送端维护两个状态变量一个是SRTT(smoothed round-trip time)一个是RTTVAR (round-trip   time variation),另外还有一个TCP时钟粒度G。

  • 1)、在没有测量到有效的RTT采样之前,设置RTO=1s;

  • 2)、在第一个有效的RTT采样测量出来后,假设采样值为R,则进行如下初始化过程

SRTT = R

RTTVAR = R/2

RTO = SRTT + max(G,K*RTTVAR)

其中K = 4;

  • 3)、当随后的RTT采样R’测量到以后,按照如下更新:

RTTVAR = (1 - beta) * RTTVAR + beta * |SRTT - R'|

SRTT = (1 - alpha) * SRTT + alpha * R'

注意用于计算RTTVAR的公式中的SRTT是本次更新前的值,也就是说这两个公式的计算顺序不能颠倒。其中alpha=1/8、 beta=1/4,alpha和beta的选值允许计算机通过移位做除法的快速运算。

计算出SRTT和RTTVAR后,RTO仍旧按照如下更新:

RTO = SRTT + max (G, K*RTTVAR)

  • 4)、当RTO计算出来后,如果RTO小于1s,RTO则应该设置为1s。虽然给出的是1s的下限,但是协议允许使用更低的下限。

  • 5)、也可以对RTO设置一个上限,协议建议上限至少为60s。

关于上面的RTT采样,协议要求使用karn算法进行采样,同时要求至少在一个RTT里面采样一次(除非因为karn算法导致不可能在一个RTT里面采样一次)。协议指出对于每个TCP报文进行RTT采样测量不一定会得到更好的RTT估计值。

2、RTO定时器的管理

协议对于RTO定时器的建议管理方法如下:

  • 1)、每次一个包含数据的TCP报文发送出去的时候(包括重传),如果RTO定时器没有运行,则重启RTO定时器,并设置定时时间为RTO。

  • 2)、当所有发出的数据报文都被ACK后,关闭这个RTO定时器。

  • 3)、当一个新的ack number到达的时候(新的ack number是指ack了新数据),如果还有未被ACK的数据,则重启RTO定时器,并设置定时时间为当前RTO。

当RTO定时器触发的时候(即所设置的定时时间到达的时候)

  • 4)、在还没有ACK的报文里面重传最早发出去的报文。

  • 5)、设置RTO = RTO * 2,这也就是我们经常说的指数回退。也可以和上面RTO更新过程一样添加一个同样的上限来限制RTO大小。

  • 6)、重启RTO定时器,设置定时时间为RTO(这里的RTO是已经回退过的RTO)。

  • 7)、如果RTO定时器是因为等待SYN报文的ACK而超时,如果实现上使用的RTO值小于3s,这个RTO定时器必须被重新初始化为3s。

    在重传完成后,新的RTT采样可能会将RTO设置为与原来比较接近的值,从而消除指数回退对于RTO的影响。另外在多次指数回退过程中,TCP实现可能会清空SRTT和RTTVAR的值,一旦这两个被清空,则需要使用上面RTO计算及更新中的第2)步来初始化SRTT和RTTVAR。

三、RTO定时器管理示例

下面的测试示例关闭了TLP功能,相关介绍见后面文章

1、RTO超时重传成功恢复后发送的新数据又RTO超时。对于这种场景我们从下图可以看到新发送的数据在RTO超时后,超时时间大约为1.5s,也就是说RTO定时器在之前指数回退后现在已经恢复。

2、RTO超时重传collapse后,只回复部分ACK确认包。如下图所示,在数据包No6超时重传的时候,把No7数据包collapse在一起了,也就是说No8重传包同时包含了No6和No7数据包的内容,从图中的len字段也可以看出来,如果这时候client只是ACK确认了No6报文的内容(No12确认包Ack=1740381487正好是No7数据包的Seq),No11重传包只有收到Ack>=1740381493时候才会取消RTO定时器,这时候部分ACK并不能取消server在发送No11时候的定时器,最终RTO超时超时重传No13数据包,重传的时候被部分ACK确认的数据不会在重传,因为No13只是重传了No7数据包。(关于重传collapse的内容我们后面内容在进行介绍)。

3、RTO超时重传成功后还有待重传数据。如下图所示,server端发出了No6和No7两个数据包,RTO超时后重传No6报文,No6重传成功后server端发现还有一个No7报文等待重传,接着在收到No11确认包后立即进行了一个快速重传。(严格的说应该叫做慢启动重传SlowStartRetrans,但是实际上走的是快速重传的流程,快速重传请参考后面的内容)。快速重传的同时会初始化一个RTO定时器,如果快速重传失败,接着进行RTO超时重传(No13-No17)。这里可以看到server端在发出No12报文时候初始化的RTO定时器定时时间为1.5s。也就是之前RTO指数回退的作用已经消除了,可以看到这里与协议是存在一些差异的。

4、SACK reneging下RTO超时重传的示例请参考后面SACK和FACK相关的内容。

TCP系列13—重传—3、协议中RTO计算和RTO定时器维护的更多相关文章

  1. TCP系列15—重传—5、Linux中RTO的计算

    之前我们介绍的都是协议中给出的RTO计算方法,下面我们看一下linux实现中RTO的计算方法.在linux中维护了srtt.mdev.mdev_max.rttvar.rtt_seq几个状态变量用来计算 ...

  2. TCP系列25—重传—15、DSACK虚假重传探测

    一.DSACK介绍 RFC2883通过指定使用SACK来指示接收端的重复包(duplicate packet)扩展了RFC2018对SACK选项的定义(SACK选项的介绍和示例参考前面内容).RFC2 ...

  3. TCP系列11—重传—1、TCP重传概述

    在最开始介绍TCP的时候,我们就介绍了TCP的三个特点,分别是面向连接.可靠.字节流式.前面内容我们已经介绍过了TCP的连接管理,接下来的这部分内容将会介绍与TCP可靠性强关联的TCP重传. 很多网络 ...

  4. TCP系列24—重传—14、F-RTO虚假重传探测

    一.虚假重传 在一些情况下,TCP可能会在没有数据丢失的情况下初始化一个重传,这种重传就叫做虚假重传(Spurious retransmission).发生虚假重传的原因可能是包传输中重排序.传输中发 ...

  5. TCP系列16—重传—6、基础快速重传(Fast Retransmit)

    一.快速重传介绍 按照TCP协议,RTO超时重传是一个非常重要的事件,当RTO超时的时候,TCP会同时通过两种方式非常谨慎的降低发送数据包的速率,一种是基于拥塞控制削减发送窗口的大小,另外一个是通过指 ...

  6. TCP系列14—重传—4、Karn算法和TSOPT的RTTM

    一.Karn算法 在RTT采样测量过程中,如果一个数据包初传后,RTO超时重传,接着收到这个数据包的ACK报文,那么这个ACK报文是对应初传TCP报文还是对应重传TCP报文呢?这个问题就是retran ...

  7. TCP系列21—重传—11、TLP

    一.介绍 Tail Loss Probe (TLP)是同样是一个发送端算法,主要目的是使用快速重传取代RTO超时重传来处理尾包丢失场景.在一些WEB业务中,如果TCP尾包丢失,如果依靠RTO超时进行重 ...

  8. TCP系列01—概述及协议头格式

    一.TCP简单介绍 我们经常听人说TCP是一个面向连接的(connection-oriented).可靠的(reliable).字节流式(byte stream)传输协议,  TCP的这三个特性该怎么 ...

  9. TCP系列12—重传—2、Linux超时重传引入示例

    在前面我们概述了TCP的超时重传之后我们简单的看一下tcp超时重传的示例.首先简单的描述一下测试过程 1.设置/proc/sys/net/ipv4/tcp_early_retrans为2,关掉TLP功 ...

随机推荐

  1. mybatis报错:未找到参数导致绑定异常

    问题: 在映射文件中使用parameterMap元素时出现以下异常: org.mybatis.spring.MyBatisSystemException: nested exception is or ...

  2. 最新版的stm32f1xx.h文件中取消了u8, u16, u32的类型定义

    使用芯片stm32f103zet6和stm32l151c8t6,在移植程序时发现,编译器提示u8未定义: 在Keil MDK 开发环境里,st定义无符号32位整形数据有很多种表示方法: 1 unsig ...

  3. C语言实现 "谁是凶手?"

    日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个.以下为4个嫌疑犯的供词.A说:不是我.   a=0B说:是C.   c=1 C说:是D.      d=1D说:C在胡说    ...

  4. HttpClient的Content-Type设置

    HttpClient的Content-Type设置 最近在对接公司内容的一个云服务的时候,遇到一个问题,就是如果使用HttpClient如何设置post时候的Content-Type? public ...

  5. [Real World Haskell翻译]第20章 Haskell系统编程

    第20章 Haskell系统编程 到目前为止,我们已经讨论了大多数的高层次的概念.Haskell也可以用于较低级别的系统编程.很可能是用haskell编写出底层的与操作系统接口的程序. 在本章中,我们 ...

  6. linux 网络编程 1---(基本概念)

    1.TCP和UDP协议 共同点:同为传输层协议 不同点: TCP:有连接,可靠 UPD 无连接,不保证可靠 TCP(即传输控制协议): 是一种面向连接的传输层协议,它是能提供高可靠性通信(即,数据无误 ...

  7. BZOJ1029_建筑抢修_KEY

    题目传送门 这是一道贪心的问题. 总体做法是这样的:先按照报废的快慢从小到大SORT一遍,优先修报废快的.同时开一个大根堆(C++的朋友可以用priority_queue),用来记录已经修了的建筑的耗 ...

  8. LeetCode:34. Search for a Range(Medium)

    1. 原题链接 https://leetcode.com/problems/search-for-a-range/description/ 2. 题目要求 给定一个按升序排列的整型数组nums[ ]和 ...

  9. spring-boot日志操作

    SpringBoot Logback日志配置 Logback的配置介绍: 1.Logger.appender及layout Logger作为日志的记录器,把它关联到应用的对应的context上后,主要 ...

  10. 【原创】MyEclipse反编译添加jadclipse_3.3.0 曲折的完美解决

    本人QQ:9715234 (java屌丝一枚) 共三部分 一.下载两个文件exe和jar 1.http://nchc.dl.sourceforge.net/project/jadclipse/jadc ...