4.滑动窗口
前提条件
确认应答机制下,每次发送方收到一个ack才会发下一个,导致大量的时间浪费在等待ack上了。
此处等待消耗的时间成本是非常多了。
希望保证可靠传输的前提下,能够让效率尽量高点,让消耗的时间成本尽可能少点。
滑动窗口提出就是为了解决上述问题的。
滑动窗口可以在保证可靠传输的基础上,提高效率(降低损失,不是增加速度)
(虽然通过这个机制,提高了效率,但不可能高于UDP)
引入滑动窗口:
批量传输:之前发了一个数据,等待ack再发下一条数据。现在先发一个数据,不等ack,再发下一个,继续再往下发。连续发了一定的数据后,同一等一次ack。
把多次请求的等待时间,使用同一份时间来等了,减少了总等待时间。
这四份数据是已经批量传输出去了,传输出四份数据之后,就等待ack,暂时先不传了,就把白色的区域,称为“窗口大小”
批量发四个数据,对应4个ack,不一定同时到达,有先有后。等一个ack回来了,就往后发一组。上述发送/返回ack的过程是很快的。
窗口往后移动的速度很快,直观上感觉是一个“滑动”效果,称为“滑动窗口”。
出现丢包,解决方法
1.ack丢了
这种情况下无需进行任何处理,对于可靠性没有影响,不需进行重传。
2.数据丢了
收到三个相同的确认应答时,进行重传
解决该问题的关键要点是:此处返回的应答报文是1001确认序号。(明确告诉对方想要的是1001)
反复索要,就是在给1001的到达留有等待时间。连续多次索要发现1001还没到,应该就是丢了,相当于“超时时间”判定。
在上述重传过程中,整体的效率是非常高的。这里的重传做到了“针对性”的重传,哪个丢了就重传哪个,已经收到的 数据,是不必要重传的,整体的效率没有额外损失,称为“快速重传”。
确认应答 超时重传 滑动窗口 快速重传 => 并不冲突,同时存在
滑动窗口也有确认应答,只不过把等待策略稍作调整,转成批量的了。批量的前提是短时间发了很多数据。如果发的数据少了,滑动窗口滑不起来,退化成了确认应答。
如果当前传输过程是按照滑动窗口(短时间传输大量数据)就按照快速重传,保证可靠性,此时丢包的标准就是看连续有多个ack索要同一个数据。
如果当前传输过程不是按照滑动窗口(没有很多数据)此时仍按超时重传,保证可靠性,此时丢包的标准就是看达到超时时间没有ack到达。
5.流量控制
通过滑动窗口可以提高传输效率,窗口大小越大,更多的数据复用同一块时间等待,效率就高了(传输多少数据不需要等待ack,此时数据的量为“窗口大小”,窗口不能无限大,因为:可靠传输的前提:任何提高效率的行为,不能影响可靠性)
发送的速度不能无限大,此时需要考虑一些情况,保证可靠性。
例如:发的快了,接收方处理不过来,也会丢包(接收方接收缓冲区满了,继续发会丢包)
如果接收缓冲区满了丢包了,就算重传也没有用,反而会浪费硬件资源。
与其等到接受方满了,再不发,不如提前就感知到,减慢速度,让发送方发送速度和接收方处理速度一致,就接受方反过来影响发送方速度 => 流量控制
通过这个字段来给发送方反馈发送速度
在普通报文中无意义,在ack报文中才有意义。
通过这个大小反馈给发送方接下来要发送的窗口设置为多少合适。
接收方会按照自己接收缓冲区剩余空间大小,作为ack中的窗口大小的数值,下一步发送方就会根据这个数值来调整自己的窗口大小。
当窗口大小为0,意味着接收缓冲区满了,此时发送方就应该暂停发送
发送方会周期性的触发“窗口探测包”并不携带载荷,这样的包对于业务并不影响,只是触发了ack,一旦查询出来的结果是非0了,发送方就继续发送。
如果当前接收方处理速度很快,但中间通信路径处了问题,某个地方堵车了,发送速度再快也没用=> 木桶效应
针对这种情况,核心思路:把中间路径经过的所有设备看成一个整体,然后通过“实验”的方式,找到一个比较合适的传输速率。
如果按照某个窗口大小发送数据之后,出现丢包,就视为中间路径存在拥堵,就减少窗口大小,如果没有出现丢包,就视为不拥堵,就增加窗口大小。
上述方案,一方面简化了问题,一方面也能很好的适应,当前网络环境的复杂性,中间这些节点,啥时间拥堵/不拥堵是“随机”的。
此时按照上述策略,就可以让发送速率动态变化。