发送方不能无脑的发数据给接收方,要考虑接收方处理能力。

    如果一直无脑的发数据给对方,但对方处理不过来,那么就会导致触发重发机制,从而导致网络流量的无端的浪
    费。

    为了解决这种现象发生,TCP 提供一种机制可以让「发送方」根据「接收方」的实际接收能力控制发送的数据量, 这就是所谓的流量控制。

    **流量控制就是让发送方的发送速率不要太快,让接收方来得及接收。如果接收方来不及接收发送方发送的数据,那么就会有分组丢失。在 TCP 中利用可边长的滑动窗口机制可以很方便的在 TCP 连接上实现对发送方的流量控制。主要的方式是接收方返回的 ACK 中会包含自己的接收窗口大小,以控制发送方此次发送的数据量大小(发送窗口大小)。

    下面举个栗子,为了简单起⻅,假设以下场景:

    • 客户端是接收方,服务端是发送方
    • 假设接收窗口和发送窗口相同,都为 200
    • 假设两个设备在整个传输过程中都保持相同的窗口大小,不受外界影响

    image.png
    image.png

    TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间再减少缓 存,这样就可以避免了丢包情况。

    窗口关闭潜在的危险
    接收方向发送方通告窗口大小时,是通过 ACK 报文来通告的。
    那么,当发生窗口关闭时,接收方处理完数据后,会向发送方通告一个窗口非 0 的 ACK 报文,如果这个通告窗口 的 ACK 报文在网络中丢失了,那麻烦就大了。
    这会导致发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如不采取措施,这种相互等待 的过程,会造成了死锁的现象。

    image.png**TCP 是如何解决窗口关闭时,潜在的死锁现象呢?
    为了解决这个问题,TCP 为每个连接设有一个持续定时器,**只要 TCP 连接一方收到对方的零窗口通知,就启动持 续计时器。


    如果持续计时器超时,就会发送
    窗口探测 ( Windowprobe ) 报文**,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。
    image.png

    • 如果接收窗口仍然为 0,那么收到这个报文的一方就会􏰀新启动持续计时器;
    • 如果接收窗口不是 0,那么死锁的局面就可以被打破了。

    窗口探测的次数一般为 3 次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的 话,有的 TCP 实现就会发 RST 报文来中断连接。