TCP系列12—重传—二、Linux超时重传引入示例

        在前面咱们概述了TCP的超时重传以后咱们简单的看一下tcp超时重传的示例。首先简单的描述一下测试过程linux

一、设置/proc/sys/net/ipv4/tcp_early_retrans为2,关掉TLP功能(后面内容介绍TLP)。设置/proc/sys/net/ipv4/tcp_retries2为8,减小重传次数,这样方便wireshark抓包演示。同时设置/proc/sys/net/ipv4/tcp_discard_on_port为9877,以让client能够精确的控制发出的TCP报文,而不受到内核TCP模块的影响。服务器

二、client经过raw socket直接在IP层之上构造TCP报文,与server经过三次握手创建链接,其中client为127.0.0.1:10000,server为127.0.0.1:9877。这个步骤对应No1--No3报文。网络

三、TCP链接创建后client发送"hello"消息给服务器,服务器则回复ACK,这个步骤对应No4--No5报文。socket

四、server发送“hello”给client,这个步骤对应No6报文。tcp

五、client收到server的"hello"报文后,直接丢弃并不回复ACK。测试

六、server在没有收到ACK报文的状况下,过了大约1.5s后,server端RTO超时,触发超时重传。client一样在收到这些重传报文的时候直接丢弃而不回复ACK,这样server持续重传。一共重传了6次。spa

这个过程的wireshark截图以下(为了方便观察RTO,我把No6初传设置为时间参考点,后面数据包的Time时间都是相对于No6包的时间):code

从这个超时重传示例中咱们重点关注几个方面orm

一、能够看到No7第一次重传与No6初传间隔大约为1.5s,No8第二次重传与No7时间间隔大约是3.0s,No9第三次重传与No8时间间隔大约是6.0s。能够看到每次重传后,重传的时间间隔(即RTO)都是上次重传时间间隔的2倍。实际咱们从server端程序能够获取到Linux内核中TCP模块计算的RTO分别为1.504s、3.008s、6.016s。也能够精确的看到RTO的倍增关系。这种RTO倍增关系就是指数回退(binary exponential backoff)server

二、咱们在测试过程描述中说明设置tcp_retries2为8,而从wireshark中能够看到实际只是发生了6次重传。实际上linux内核会根据tcp_retries2计算出一个timeout,计算方式以下面代码所示,其中对于established状态下的endpoint,rto_base为200ms,TCP_RTO_MAX为120000ms。当tcp_retries2设置为8的时候,按照下面流程计算得出timeout=102.2s。其中No11和No12之间的RTO为48s左右(根据server端实际获取的信息,linux内部实际计算出的RTO为48.128s),若是进一步指数回退,则下一次重传时间点大约是48*2+94=190s,能够看到190s已经超过了计算出的timeout(即102.2s)值,应该不会进一步进行重传,屡次超时重传失败server端则会直接释放这个tcp链接,释放这个链接后若是server端尝试进一步写入数据就会返回ETIMEDOUT的错误

 
 
 
 
if (tcp_retries2 <= 9) timeout = ((2 << tcp_retries2) - 1) * rto_base; else timeout = ((2 << 9) - 1) * rto_base + (tcp_retries2 - 9) * TCP_RTO_MAX;

在RFC1122中有两个门限R1和R2,当重传次数超过R1的时候,TCP向IP层发送negative advice,指示IP层进行MTU探测、刷新路由等过程,以防止因为网络链路发生变化而致使TCP传输失败。当重传次数超过R2的时候,TCP放弃重传并关闭TCP链接。其中R1和R2也能够表述为时间,即总重传时间超过R1或者R2的时候触发响应的操做。在linux中对于普通数据报文状态下的TCP,R1对应/proc/sys/net/ipv4/tcp_retries1,R2对应/proc/sys/net/ipv4/tcp_retries2参数。这两个参数都是根据上面的计算流程计算出一个timeout值,当总重传时间超过这个timeout值尚未收到ack的时候触发响应的操做。对于SYN报文如咱们以前所讲,则是由tcp_syn_retries和tcp_synack_retries这两个参数控制


补充说明:

一、linux中根据tcp_retries1和tcp_retries2计算timeout的过程参考代码retransmits_timed_out。

二、网上不少资料以及man 7 tcp和第二版的tcpip详解中对于tcp_retries1或tcp_retries2描述都是按照重传次数来描述的,其实是错误的。






相关文章
相关标签/搜索