TCP协议-----《第二篇》重传机制

我们都知道TCP的可靠传输是确认号来实现的,那么TCP的确认机制是怎样的呢?是收到一个包就马上确认,还是可以稍等一下在确认呢?所以我们就要先说一下TCP的延迟确认机制:

按照TCP协议,确认机制是累积的,也就是确认号X的确认指示的是所有X之前但不包括X的数据已经收到了。确认号(ACK)本身就是不含数据的分段,因此大量的确认号消耗了大量的带宽,虽然大多数情况下,ACK还是可以和数据一起捎带传输的,但是如果没有捎带传输,那么就只能单独回来一个ACK,如果这样的分段太多,网络的利用率就会下降。为缓解这个问题,RFC建议了一种延迟的ACK,也就是说,ACK在收到数据后并不马上回复,而是延迟一段可以接受的时间,延迟一段时间的目的是看能不能和接收方要发给发送方的数据一起回去,因为TCP协议头中总是包含确认号的,如果能的话,就将数据一起捎带回去,这样网络利用率就提高了。

延迟ACK就算没有数据捎带,那么如果收到了按序的两个包,那么只要对第二包做确认即可,这样也能省去一个ACK消耗。由于TCP协议不对ACK进行ACK的,RFC建议最多等待2个包的积累确认,这样能够及时通知对端Peer,我这边的接收情况。Linux实现中,有延迟ACK和快速ACK,并根据当前的包的收发情况来在这两种ACK中切换。一般情况下,ACK并不会对网络性能有太大的影响,延迟ACK能减少发送的分段从而节省了带宽,而快速ACK能及时通知发送方丢包,避免滑动窗口停等,提升吞吐率。

关于ACK分段,有个细节需要说明一下,ACK的确认号,是确认按序收到的最后一个字节序,对于乱序到来的TCP分段,接收端会回复相同的ACK分段,只确认按序到达的最后一个TCP分段。TCP连接的延迟确认时间一般初始化为最小值40ms,随后根据连接的重传超时时间(RTO)、上次收到数据包与本次接收数据包的时间间隔等参数进行不断调整。

TCP要保证所有的数据包都可以到达,所以,必需要有重传机制。

《一》超时重传

TCP的重传是由超时触发的,这会引发一个重传选择问题,假设TCP发送端连续发了1、2、3、4、5、6、7、8、9、10共10包,其中4、6、8这3个包全丢失了,由于TCP的ACK是确认最后连续收到序号。
这样发送端只能收到3号包的ACK,这样在TIME_OUT的时候,发送端就面临下面两个重传选择:
1)仅重传4号包;

2)重传3号后面所有的包,也就是重传4~10号包。

对于,上面两个选择的优缺点都比较明显:
方案[1]-优点:按需重传,能够最大程度节省带宽。缺点:重传会比较慢,因为重传4号包后,需要等下一个超时才会重传6号包;方案[2]-优点:重传较快,数据能够较快交付给接收端。缺点:重传了很多不必要重传的包,浪费带宽,在出现丢包的时候,一般是网络拥塞,大量的重传又可能进一步加剧拥塞。

上面的问题是由于单纯以时间驱动来进行重传的,都必须等待一个超时时间,不能快速对当前网络状况做出响应,如果加入以数据驱动呢?TCP引入了一种叫Fast Retransmit(快速重传 )的算法,就是在连续收到3次相同确认号的ACK,那么就进行重传。这个算法基于这么一个假设,连续收到3个相同的ACK,那么说明当前的网络状况变好了,可以重传丢失的包了。
《二》快速重传

快速重传不以时间驱动,而以数据驱动重传。也就是说,如果包没有连续到达,就ack最后那个可能被丢了的包,如果发送方连续收到3次相同的ack,就重传,它的好处就是不用等timeout了再重传。

比如:如果发送方发出了1,2,3,4,5份数据,第一份先到送了,于是就ack回2,结果2因为某些原因没收到,3到达了,于是还是ack回2,后面的4和5都到了,但是还是ack回2,因为2还是没有收到,于是发送端收到了三个ack=2的确认,知道了2还没有到,于是就马上重转2。然后,接收端收到了2,此时因为3,4,5都收到了,于是ack回6。示意图如下:

快速重传只解决了一个问题,就是timeout的问题,它依然面临一个艰难的选择,就是是重传之前的一个还是重传所有的问题。对于上面的示例来说,是重传#2呢还是重传#2,#3,#4,#5呢?因为发送端并不清楚这连续的3个ack(2)是谁传回来的?也许发送端发了20份数据,是#6,#10,#20传来的呢。这样,发送端很有可能要重传从2到20的这堆数据(这就是某些TCP的实际的实现)。出现难以决定是否重传多个包问题的根源在于,发送端不知道那些非连续序号的包已经到达接收端了,但是接收端是知道的,如果接收端告诉一下发送端不就可以解决这个问题吗?

《三》SACK

SACK是TCP的扩展选项,包括:
                                              1)SACK允许选项(Kind=4,Length=2,选项只允许在有SYN标志的TCP包中);

                                              2)SACK信息选项(Kind=5,Length)。

ACK还是Fast Retransmit的ACK,SACK则是汇报收到的数据碎版。参看下图:

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

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

SACK依靠接收端的接收情况反馈,解决了重传风暴问题,这样够了吗?接收端能不能反馈更多的信息呢?显然是可以的,于是,RFC2883对对SACK进行了扩展,提出了D-SACK,也就是利用第一块SACK数据中描述重复接收的不连续数据块的序列号参数,其他SACK数据则描述其他正常接收到的不连续数据。这样发送方利用第一块SACK,可以发现数据段被网络复制、错误重传、ACK丢失引起的重传、重传超时等异常的网络状况,使得发送端能更好调整自己的重传策略。

《四》D-SACK,有几个优点:
1)发送端可以判断出,是发包丢失了,还是接收端的ACK丢失了。(发送方,重传了一个包,发现并没有D-SACK那个包,那么就是发送的数据包丢了;否则就是接收端的ACK丢了,或者是发送的包延迟到达了);

2)发送端可以判断自己的TIME_OUT是不是有点小了,导致过早重传(如果收到比较多的D-SACK就该怀疑是TIME_OUT小了);

3)发送端可以判断自己的数据包是不是被复制了。(如果明明没有重传该数据包,但是收到该数据包的D-SACK);

4)发送端可以判断目前网络上是不是出现了有些包被延迟了,也就是出现先发的包却后到了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值