流水线可靠数据传输协议
rdt3.0虽然是一个正确的协议,但是很多人对于它的性能并不是很满意,因为它基于停等协议。而且是发送一个报文,就需要等待对方回复后才可以发送下一个,这很大程度上会影响性能。

对此最简单的解决办法是,发送一个报文段后并不等待回复,而是继续发送,累计N个报文段后再等待对方回复,这样效率就会提高。如下图所示:

这种技术也被称为流水线。有如下要求:
1、必须增加序号范围,而且每个分组有一个唯一的序号,用于确认是否正确传输。
2、协议的发送方和接收方都需要缓存多个分组,发送方需最低要缓存已经发送的但是对方还没确认的报文,用于重新发送。
3、解决流水线的差错恢复有两种基本方法:回退N步和选择重传
回退N步(GBN)
该协议中,允许发送方发送N个分组而不需要等待确认。这里的N一般称为窗口长度,如果窗口里面的数据都没有被确认,则无法继续发送,如果有数据确认,则窗口向前移动,继续发送数据。如下图所示:

该协议也被称为滑动窗口协议。该协议的发送方必须响应以下三类事件:
1、上层的调用。当上层调用时,发送方先检查窗口是否已满,即是否有N个数据未确认。如果没满,就产生分组并且发送,并更新变量。如果满了,就告诉上层窗口已满,让它过一段时间重试。
2、接受一个ACK。该协议中对序号为n的分组采用累计确认的方式,表明接收方已经接收到序号为n以前包括序号为n的所有分组。
3、超时事件。如果发送的数据超过一定时间还未收到回复,那么就需要重传所有已经发送但是还未确认收到的数据。
接收方也会有对应的要求:
如果接受方正确接收到一个分组为n的分组(即上一次交给应用层的分组号是n - 1),则会给发送方回复一个ACK,并将分组交给上层,其他情况都会丢弃该分组。因为接收方发送序号为n的ACK,意味着n以及n以前的数据都正确接收。
即接收方的逻辑如下图所示:

选择重传
上述协议虽然提升了性能,但是也存在一些问题。比如,当窗口和带宽的时延比较大的时候,中间有一个分组的差错,就会导致大量的重传。
而选择重传就是只重传错误的分组,而不是重传某一个错误分组以后的所有分组。该协议的实现需要接收方也缓存一部分的数据,而且也要有窗口。

具体来说就是缓存那些乱序到达的数据,比如现在已经确认接收了需要为3的分组,而分组4丢失了,此时又接收到了分组5以及后续的数据。此时分组5以及以后的都会被缓存,直到接收到4后,才会从缓存中按序读取,然后交付给上层。具体过程如下:
由上图可以看出,发送方和接收方的窗口内的数据并不总是一样的,这也就会导致以下问题:
如何判断一个分组是重传还是一个新的分组呢?
考虑下面例子中可能发生的情况,该例有包括4个分组序号0、1、2、3的有限序号范围且窗口长度为3。假定发送了分组0至2,并在接收方被正确接收且确认了。此时,接收方窗口落在第4、5、6个分组上,其序号分别为3、0、1。
现在考虑两种情况,第一种如下图:
对前3个分组的ACK丢失,因此发送方重传这些分组,接收方下一步要接收序号为0的分组,而他期望的分组却是序号为3的,而且它无法发现这是重传的前三个已经接收的分组,而会当作是分组3丢失,等待重传3,而接收传送过来的0和1,将他们放在缓存当中。

下图的情况是,对前3个分组的ACK都被正确交付。因此发送方向前移动窗口并发送第4、5、6个分组,其序号分别为3、0、10序号为3的分组丢失,但序号为0的分组到达(一个包含新数据的分组)。
这时候接收方收到序号为0的分组时,他无法判断发送方是重发自己已经接收的序号0还是新发送的序号为0的分组。

显然,窗口长度比序号空间小1时协议无法工作。窗口长度必须小于或等于序号空间大小的一半。