目录
一、滑动窗口的来由
TCP由于存在确认应答机制,在一方发出一条消息以后,另一方要发送ACK表明自己收到消息。如果按照下面这种形式,每次收到ACK才发出下一条消息,这种一发一收的效率太低。但是如果客户端不急着接收ACK,可以利用等待ACK的空挡直接发送下一批数据,这样就可以做到短时间内发送多批数据。这就是滑动窗口的基本思想。
窗口大小就是 这几批数据的所占字节数,以下面这个为例,窗口大小就是3000。在发送前三批数据的时候,可以不用等待ACK直接发送。
注意:
一次不能发送太多,因为要看对方接收缓冲区的接受能力。
二、滑动窗口
假设发送缓冲区是一个大数组,数组的每一个位置是以字节为单位的。我们将发送缓冲区分为三个部分:
第一部分
是存放已经发送而且收到ACK的数据,假设是0~1000个字节;
第二部分
存放准备发送或者已经发送但没有收到ACK的数据,假设是1001~4000个字节;
第三部分
存放尚未发送的数据(短时间内不会发送),假设是4001~ 5000 个字节;
1、滑动窗口模型
滑动窗口控制着我们每次所能发送的数据量,避免发送的数据量超出对方的接收能力。滑动窗口滑动的基本思想如下:
(1) 客户端将1001~4000 的数据分三批发送,即1001~2000、2001~3000、3001~4000。当客户端收到了1001~2000的ACK时,此时滑动窗口的左边界向右移动1000个字节;
(2) 如果ACK报文中的“16位窗口大小”的字段表明对方的接收缓冲区剩余空间为500字节,说明接收方还能再发500字节,那么滑动窗口的右边界向右移动500字节.
因此,滑动窗口就结果而言,看起来像是在滑动,其本质是 根据是否收到ACK以及对方接收缓冲区的大小来移动左右边界。
2、滑动窗口可能出现的状况
上面只是做了一个简单的介绍,实际过程中可能会遇到很多种情况,这里我们从两个问题来了解滑动窗口的作用过程:第一个点是,中间的报文丢了,即2001~3000的报文丢了;第二个点是后发送的先收到了ACK,即没有收到2001~3000,但是收到了3001~4000的报文的ACK。
(1) 客户端发送的报文丢了(快重传机制)
ACK确认应答机制中有一个很关键的点就是,接收方必须是按序回复。假设服务端收到了1001~2000、3001~4000的数据,但是没有收到2001~3000的数据。
– 服务端收到了1001~2000的数据,那就
回复确认序号2001+ACK,表明2001之前的数据已经全部收到,下一次从2001的字节位置开始发
;
– 服务端没有收到2001~3000,此时服务端不会发送ACK;
– 服务端即便收到了3001~4000的数据,等了一段时间依然没有收到2001~3000的数据,说明2001~3000的报文丢了。此时发送的确认序号不是4001,而是2001,表明目前只收到了2001之前的数据。
现在站在客户端的角度,客户端如果
连续多次(一般是连续三次)收到了2001的确认应答
,说明序号为2001之后的报文丢了,此时就会重传2001~3000的报文。服务端收到2001~3000的报文以后,由于之前已经收到了3001~4000 的报文(暂时存放在接收缓冲区),那么服务端相当于已经收到了全部的报文,此时服务端发送的确认序号是 4001,表明4001之前的报文已经全部收到,下一次可以从第4001个位置开始发。
这种重发机制被称为“
快重传
”,与超时重传不同的是,超时重传是等待60s以后还没有收到ACK,此时客户端就会重新发送报文;而快重传更注重效率,只要收到多个相同的确认序号,就立马重传。
(2) 服务端发送的ACK丢了(先收到了排序靠后的ACK)
现在服务端是正常收到了三批数据,并一一发送确认应答,但是客户端仅收到了1001~2000、3001~4000的ACK,说明2001~3000要么丢了,要么因为网络状况延迟到达。
– 客户端收到了1001~2000,此时滑动窗口的左边界向左移动1000个字节;根据缓冲区剩余空间大小移动右边界。
– 客户端没有收到2001~3000,但是收到了3001~4000的ACK。没关系,因为服务端必须是按序号回复的,如果服务端没有收到2001~3000的数据,根本不会发送3001~4000的ACK,因此可以认为 服务端已经收到了三批数据。此时滑动窗口的左边界向左移动至4001,同时根据对方接收缓冲区剩余空间大小移动右边界。
三、滑动窗口大小为0时,何时才能继续发送数据?
如果对方上层的处理速度较慢,导致对方接收缓冲区里的数据没有被取走,滑动窗口只有左边界在移动,滑动窗口的大小很快就会变成0。为了应对这种情况,TCP有两种策略。
1、策略一:发送方定期发送不携带数据的报文
发送方定期可以发送一个不携带数据的报文,报文不携带数据,也就不会占用服务端的缓冲区,接收方返回的ACK中会携带窗口大小,以此来判断是否可以继续发送数据。
2、策略二:接收方缓冲区一旦更新立马通知发送方
接收方的上层把数据取走的时候,服务端主动发送一个窗口更新的通知报文,该报文不携带任何数据,只是在报文首部设置了16位窗口大小
注意
:在实际使用时,一般是两种方式同时使用。
四、总结
第一,滑动窗口是发送缓冲区的一部分,控制着每次所能发送数据量的最大值。
第二,滑动窗口的大小跟对方的接收能力有关,滑动窗口的大小不是固定的。如果对方上层一直不读取数据,对方的缓冲区剩余空间大小一直在减少,滑动窗口的大小也一直在减小。(其实接收能力还跟网络状况有关,这个就留到TCP拥塞控制说明)