前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TCP重传分析

TCP重传分析

原创
作者头像
ivanlwyan
发布2018-08-24 19:44:49
7.8K0
发布2018-08-24 19:44:49
举报
文章被收录于专栏:ivan空间ivan空间

1,重传基本原理

TCP协议是一种面向连接的可靠的传输层协议,它保证了数据的可靠传输。既然是可靠的传输,那对于丢包情况肯定有一套重传的机制。

TCP重传的基本原理:在发送一个数据之后,就开启一个定时器,若是在这个时间内没有收到发送数据的ACK确认报文,则对该报文进行重传。

上面的时序图,就是TCP重传的全部内容吗?好像很简单啊。

答案是:当然不是。

我们考虑一下下面这些问题:

1)RTO的时间是怎么来的?

2)每发一个包,都会启动一个定时器吗?那会不会导致定时器特别多,对系统性能有影响?

3)每个丢包都需要RTO超时之后,才能重传吗?对于偶尔丢了一个包,后面包都收到的场景,是否可以快速检测到该场景,并快速重传?

4)前面一个包丢了,后面所有的包都需要重传,即使已经发送成功;是否可以做到只重传已丢包的包,对于已收到的包不需要重传?

下面我们就来深入的讨论TCP重传机制的细节和原理,解决上面提到的问题。

2,RTO计算方法

RTO:英文全称是Retransmission TimeOut,即重传超时时间;

RTO是一个动态值,会根据网络的改变而改变。RTO是根据给定连接的往返时间(RTT,全称:Round Trip Time)的测量值而计算出来的。

那么RTT又是如何测量得到的呢?

有有种测量方法:

1)重传队列中数据包的TCP控制块

TCP每发送一个数据包,就会把该数据包复制一份放到TCP重传队列中,数据包skb中的TCP控制块包含着一个变量tcp_skb_cb->when,记录了该数据包的第一次发送时间;收到该数据包的ACK时,再根据:当前时间 - when,得到RTT时间;

2)开启TCP Timestamp选项

需要开启tcp_timestamps选项,可以通过sysctl命令修改和查看;

当接收端和发送端同时支持TCP时戳选项时,发送端记录在TCP包头选项内的时戳可以被接收端随响应反射回来,发送端就可以利用响应报文的反射时戳计算出某个TCP包的即时往返传输时间。

RTT = 当前时间 -  数据包中Timestamp选项的回显时间 这个回显时间是该数据包发出去的时间,知道了数据包的接收时间(当前时间)和发送时间(回显时间),就可以轻松的得到RTT的一个测量值。

既然不用TCP Timestamp选项就能测量出RTT,为什么还要多此一举?

因为根据TCP Timestamp测出来的RTT更加准确;对于重传的数据包的响应,重传队列方法并不知道重传的开始时间,所以没办法采集起来作为一个样本;而TCP Timestamp方法则可以。

根据RTT计算RTO的方法:

RTO = srtt >> 3 + rttvar

RTO计算时,使用了一次指数平滑算法。

srtt为经过平滑后的RTT值,它代表着当前的RTT值,每收到一个ACK更新一次。 为了避免浮点运算,它是实际RTT值的8倍。 mdev为RTT的平均偏差,用来衡量RTT的抖动,每收到一个ACK更新一次。 mdev_max为上一个RTT内的最大mdev,代表上个RTT内时延的波动情况,有效期为一个RTT。 rttvar为mdev_max的平滑值,可升可降,代表着连接的抖动情况,在连接断开前都有效

3,超时定时器的实现

具体的TCP协议实现中,并不是每一个包都有一个定时器;如果每一个包都有一个定时器,那系统中定时器数据就太多了,会消耗很多资源,性能会比较差;

所以,TCP的实现中,都是一个连接对应一个超时定时器;

那一个连接对应一个定时器,那一个数据包的超时时间严格等于RTO时间吗?答应是:一个连接只有一个超时定时器,那么对于每个数据包,没办法做到超时时间严格等于RTO;但是可以保证超时时间不大于2*RTO。其实这就是性能和准确性的权衡考虑。

那TCP的超时定时器具体是怎实现的呢?

原则:

1.每一个报文在长期收不到确认都必须可以超时;

2.这个长期收不到中长期不能和测量的RTT相隔太远;

实现方法:

a.发送TCP分段时,如果还没有重传定时器开启,那么开启它。

b.发送TCP分段时,如果已经有重传定时器开启,不再开启它。

c.收到一个非冗余ACK时,如果有数据在传输中,重新开启重传定时器。

d.收到一个非冗余ACK时,如果没有数据在传输中,则关闭重传定时器。

根据a和c(在c中,注意到ACK是非冗余的),任何TCP分段只要不被确认,超时定时器总会超时的。然而为何需要c呢?只有规则a存在的话,也可以做到原则1。实际上确实是这样的,但是为了不会出现过早重传,才添加了规则c,如果没有规则c,那么万一在重传定时器到期前,发送了一些数据,这样在定时器到期后,除了很早发送的数据能收到ACK外,其它稍晚些发送的数据的ACK都将不会到来,因此这些数据都将被重传。

4,快速重传

因为RTO超时重传的代价是比较大,会导致拥塞控制机制进行慢启动过程。对于因为网络毛刺或者随机因素导致的偶尔单个丢包,如果也进行RTO超时重传,会影响网络传输的性能。

对于这种场景,引入了快速重传机制。

发送方连续收到3次相同的ack,这个时候即使超时定时器还没有超时,也开始启动重传。

5,选择性重传

TCP通信时,如果发送序列中间某个数据包丢失,TCP会通过重传最后确认的包开始的后续包,这样原先已经正确传输的包也可能重复发送,急剧降低了TCP性能。为改善这种情况,发展出SACK(Selective Acknowledgment, 选择性确认)技术,使TCP只重新发送丢失的包,不用发送后续所有的包,而且提供相应机制使接收方能告诉发送方哪些数据丢失,哪些数据重发了,哪些数据已经提前收到等。

1)该功能可配置,通过系统参数:net.ipv4.tcp_sack配置;使用sysctl命令修改和查看。

2)CP头里加一个SACK选项,说明了接收到的数据的区间。

3)存在接收方Reneging情况,所谓Reneging的意思就是接收方有权把已经报给发送端SACK里的数据给丢了。这样干是不被鼓励的,因为这个事会把问题复杂化了,但是,接收方这么做可能会有些极端情况,比如要把内存给别的更重要的东西。所以,发送方也不能完全依赖SACK,还是要依赖ACK,并维护Time-Out,如果后续的ACK没有增长,那么还是要把SACK的东西重传,另外,接收端这边永远不能把SACK的包标记为Ack。

4)SACK会消费发送方的资源,试想,如果一个攻击者给数据发送方发一堆SACK的选项,这会导致发送方开始要重传甚至遍历已经发出的数据,这会消耗很多发送端的资源。

6,DSACK

DSACK是在SACK的基础上做了一些扩展,主要用于对收到的重复报文进行了处理。 DSACK同样使用了与SACK一样的报文格式,唯一区别在于:第一个连续的block指定的是触发DSACK的重复报文的序号空间。

DSACK主要作用是:告诉发送方有哪些数据被重复接收了。

区分SACK和D-SACK的方法:

D-SACK使用了SACK的第一个段来做标志,

1)如果SACK的第一个段的范围被ACK所覆盖,那么就是D-SACK

2)如果SACK的第一个段的范围被SACK的第二个段覆盖,那么就是D-SACK

引入了D-SACK,有这么几个好处:

1)可以让发送方知道,是发出去的包丢了,还是回来的ACK包丢了。

2)是不是自己的timeout太小了,导致重传。

3)网络上出现了先发的包后到的情况(又称reordering)

4)网络上是不是把我的数据包给复制了。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档