我们知道TCP的传输是全双工的,不过下面的例子,为了研究的方便,假定数据传输只在一个方向上进行,即A发送数据,B接收数据。
TCP的滑动窗口是以“字节”为单位的。现在假定A收到了B发来的确认报文,其中窗口为20字节,而确认号是31(这表示B希望收到的下一个序列号是31,而序列号30为止的数据都已经收到了)。
对于发送方A来说,在没有收到B的确认的情况下,A可以连续的把窗口内的数据都发送很出去,凡是已经发送过的数据,在没有收到B的确认之前,都必须暂时保留,以便在数据丢失后做超时重传。
发送窗口中的序号表示允许发送的序号。显然,窗口越大,发送方就可以连续发送更多的数据,因而获得更高的传输效率,但前提是接收方要来得及处理这些数据。
发送方后沿后面部分表示已发送且已经收到确认。这些数据则不需要再保留了;发送方前沿的前面部分表示不允许发送的,因为接收方没有为这部分数据保留临时存放的缓存空间。
发送窗口后沿的变化情况有2种:
发送窗口的后沿不可能向后移动,因为不能撤销已收到的确认。
发送窗口前沿的变化有3种:
不动(收到新的确认,但对方通知的窗口大小变小了,使得发送窗口前沿正好不动)
前移(没有收到新的确认信息,且对方通知窗口大小不变)
后移(不推荐这样做)这发生在对方通知的窗口缩小了,但这很可能发送方在收到这个通知之前已经发送了窗口中的很多数据,现在又要收缩窗口,不让这些数据发送,这样就可能产生一些错误。
现在假定A发送了序号31-41 的数据。此时,发送窗口位置并未改变。
从上面的图可以看出,要描述一个发送窗口的状态需要3个指针:P1,P2,P3。他们表示的含义是:
小于P1的是已发送并已收到确认的部分;大于P3的是不允许发送的部分
P3-P1 表示A的发送窗口大小
P2-P1 表示已发送但未收到确认的数据
P3-P2 表示允许发送但尚未发送的数据(又称为可用窗口或有效窗口)
再看下B的接收窗口。B的接收窗口大小为20,在接收窗口外面,到30号为止的数据已经发送了确认,并已经交付给主机。因此在B中可以不用保留这些数据。图中序号31-50是允许接收的。
上图中,B收到了序号为32和33的数据,但这些数据没有按序到达(因为31的还没收到)。这里应该注意的是,B只能对按序收到的数据中的最高序号给出确认,因此B发送的确认报文段的确认号仍然是31(期望收到31的报文),而不能使32或者33。
现在假定B收到了序号为31的数据,并把序号为31-33的数据交付给主机,然后B删除这些数据。接着把接收窗口向前移动3个序号,如下图所示:
假如现在B收到了37,38和40这3个数据包,但是由于他们没有按序到达,只能暂时先存在接收窗口中。此时,由于B已经发送了31,32,33这三个数据包的确认信息,A收到B的确认信息后,发送窗口向前移动3个序号,但是P2指针不动,可发送的序号范围为42-53。
A在连续发送完42-53的数据后,指针P2向前移动和P3重合。这时候发送窗口内的序号都已用完,但暂时还没收到确认。由于A的发送窗口已满,可用窗口已减少到零,因此必须停止发送。
注意:假如发送窗口内的数据都已经正确到达B,B也已经确认,但是由于网络问题,这些确认仍然滞留在网络中。在没收到B的确认时,A不能猜测“B或许已经收到了”,而是认为B没有收到这些数据。于是A等到过了超时重传的时间后,就会重新发送这部分数据,直到收到B的确认为止。
我们之前说过,无论是发送方还是接收方,他们都有发送和接收缓存,下面简单讨论下缓存。
发送缓存用来缓存:(1)发送应用程序传送给发送方TCP准备发送的数据 (2)TCP已发送出但尚未收到确认的数据
接收缓存用来缓存:(1)按序到达的、但尚未被接收应用程序读取的数据(2)为按序到达的数据
如果收到的数据包被检测出有差错,则要丢弃。如果接收应用程序来不及读取收到的数据,接收缓存最终就会被填满,使得接收窗口减小为0。
这里有3点需要注意:
(1)虽然A的发送窗口是根据B的接收窗口而来设置的,当时同一时刻,A的发送窗口大小并不总是等于B的接收窗口大小,因为发送方与接收方的协同是依靠网络进行的,因此需要视网络状态而定。另外,A的发送窗口也可能根据网络拥塞程度适当减小。
(2)对于不按序到达的数据应该如何处理?如果接收方把不按序到达的数据一律丢弃,那么接收窗口的管理会变得简单,但是发送方A需要重复的发送已发送过的数据,这也就使得传输速率降低。因此TCP通常对不按序到达的数据是先暂时存放在接收窗口中,等到收到缺少的数据包之后,再按序交付给应用程序。
(3)TCP要求接收方必须有累积确认的功能,这可以减少传输开销。