为什么要引入滑动窗口?

最早使用停止-等待协议来实现可靠传输,即发送一个分组,确认之后再发送下一个分组。
但是停止-等待协议信道利用率很低。
为了提高信道利用率,采用流水线传输的方式:发送多个分组,进行累计确认。

但是每次发送分组的数量如何控制?
如果发送分组过多,接收端只能处理部分分组,其余分组还得超时重传重新发送,造成信道阻塞等;
如果发送分组过少,信道利用率又低。
因此,需要使用一个方法,控制每次发送分组的数量,信道利用高又不致于信道阻塞。
因此,引入了滑动窗口。

滑动窗口的具体工作方法

基本思路:接受方需要告诉发送方自己最多能接收多少数据,然后发送方根据这个值对数据发送操作进行控制。
image.png

参考:谢希仁第五版:《计算机网络》
image.png
A收到B的确认报文段,确认号是31(表明B期望收到的下一个序号是31,序号30为止的数据已经收到)。

讨论A的发送窗口。
发送窗口表示:

  • 在没有收到B的确认的情况下,A可以连续把窗口内的数据都发送出去。
  • 凡是已经发送过的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。

image.png
image.png

再看一下B的接收窗口。B的接收窗口大小是20。在接收窗口外面,到30号为止的数据是已经发送过确认,并且已经交付主机了。因此在B可以不再保留这些数据。接收窗口内的序号(31~50)是允许接收的。在图5-16中,B收到了序号为32和33的数据。这些数据没有按序到达,因为序号为31的数据没有收到(也许丢失了,也许滞留在网络中的某处)。请注意,B只能对按序收到的数据中的最高序号给出确认,因此B发送的确认报文段中的确认号仍然是31(即期望收到的序号),而不能是32或33。

image.png
现在假定B收到了序号为31的数据,并把序号为31~33的数据交付主机,然后B删除这些数据。接着把接收窗口向前移动3个序号(图5-17),同时给A发送确认,其中窗口值仍为20,但确认号是34。这表明B已经收到了到序号33为止的数据。我们注意到,B还收到了序号为37, 38和40的数据,但这些都没有按序到达,只能先暂存在接收窗口中。A收到B的确认后,就可以把发送窗口向前滑动3个序号,但指针P2不动。可以看出,现在A的可用窗口增大了,可发送的序号范围是42~53。

image.png
A在继续发送完序号42~53的数据后,指针P2向前移动和P3重合。发送窗口内的序号都已用完,但还没有再收到确认(图5-18)。由于A的发送窗口已满,可用窗口已减小到零,因此必须停止发送。请注意,存在下面这种可能性,就是发送窗口内所有的数据都已正确到达B,B也早已发出了确认。但不幸的是,所有这些确认都滞留在网络中。在没有收到B的确认时,A不能猜测:“或许B收到了吧!”为了保证可靠传输,A只能认为B还没有收到这些数据。于是,A在经过一段时间后(由超时计时器控制)就重传这部分数据,重新设置超时计时器,直到收到B的确认为止。如果A收到确认号落在发送窗口内,那么A就可以使发送窗口继续向前滑动,并发送新的数据。

返回ACK号和更新窗口的时机

更新窗口大小的时机:接受方将数据传递给应用程序,导致接受缓冲区剩余容量增加时,这个时候就需要告知发送方。
返回ACK号时机:当接收方收到数据时,如果确认内容没有问题,就应该向发送方返回ACK号,因此我们可以认为收到数据之后马上就应该进行这一操作。

如果将前面两个因素结合起来看,首先,发送方的数据到达接收方,在接收操作完成之后就需要向发送方返回ACK号,而再经过一段时间[插图],当数据传递给应用程序之后才需要更新窗口大小。但如果根据这样的设计来实现,每收到一个包,就需要向发送方分别发送ACK号和窗口更新这两个单独的包[插图]。这样一来,接收方发给发送方的包就太多了,导致网络效率下降。

因此,接收方在发送ACK号和窗口更新时,并不会马上把包发送出去,而是会等待一段时间,在这个过程中很有可能会出现其他的通知操作,这样就可以把两种通知合并在一个包里面发送了。举个例子,在等待发送ACK号的时候正好需要更新窗口,这时就可以把ACK号和窗口更新放在一个包里发送,从而减少包的数量。当需要连续发送多个ACK号时,也可以减少包的数量,这是因为ACK号表示的是已收到的数据量,也就是说,它是告诉发送方目前已接收的数据的最后位置在哪里,因此当需要连续发送ACK号时,只要发送最后一个ACK号就可以了,中间的可以全部省略。当需要连续发送多个窗口更新时也可以减少包的数量,因为连续发生窗口更新说明应用程序连续请求了数据,接收缓冲区的剩余空间连续增加。这种情况和ACK号一样,可以省略中间过程,只要发送最终的结果就可以了。