拥塞控制 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了( 六 )

拥塞控制 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了


文章图片
窗口关闭潜在的危险这会导致发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如不不采取措施,这种相互等待的过程,会造成了死锁的现象。TCP 是如何解决窗口关闭时,潜在的死锁现象呢?
为了解决这个问题,TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。如果持续计时器超时,就会发送窗口探测报文,而对方在确认这个探测报文时,给出自己现在的接收窗口大小。

拥塞控制 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了


文章图片
窗口探测如果接收窗口仍然为 0,那么收到这个报文的一方就会重新启动持续计时器;如果接收窗口不是 0,那么死锁的局面就可以被打破了。窗口探查探测的次数一般为 3 此次,每次次大约 30-60 秒。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。糊涂窗口综合症如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。要知道,我们的 TCP + IP 头有 40 个字节,为了传输那几个字节的数据,要达上这么大的开销,这太不经济了。就好像一个可以承载 50 人的大巴车,每次来了一两个人,就直接发车。除非家里有矿的大巴司机,才敢这样玩,不然迟早破产。要解决这个问题也不难,大巴司机等乘客数量超过了 25 个,才认定可以发车。现举个糊涂窗口综合症的栗子,考虑以下场景:接收方的窗口大小是 360 字节,但接收方由于某些原因陷入困境,假设接收方的应用层读取的能力如下:接收方每接收 3 个字节,应用程序就只能从缓冲区中读取 1 个字节的数据;在下一个发送方的 TCP 段到达之前,应用程序还从缓冲区中读取了 40 个额外的字节;

拥塞控制 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了


文章图片
糊涂窗口综合症每个过程的窗口大小的变化,在图中都描述的很清楚了,可以发现窗口不断减少了,并且发送的数据都是比较小的了。所以,糊涂窗口综合症的现象是可以发生在发送方和接收方:接收方可以通告一个小的窗口而发送方可以发送小数据于是,要解决糊涂窗口综合症,就解决上面两个问题就可以了让接收方不通告小窗口给发送方让发送方避免发送小数据怎么让接收方不通告小窗口呢?
接收方通常的策略如下:当「窗口大小」小于 min ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为 0,也就阻止了发送方再发数据过来。等到接收方处理了一些数据后,窗口大小 >= MSS,或者接收方缓存空间有一半可以使用,就可以把窗口打开让发送方发送数据过来。【拥塞控制 你还在为 TCP 重传、滑动窗口、流量控制、拥塞控制发愁吗?看完图解就不愁了】怎么让发送方避免发送小数据呢?
使用 Nagle 算法,该算法的思路是延时处理,它满足以下两个条件中的一条才可以发送数据:要等到窗口大小 >= MSS 或是 数据大小 >= MSS收到之前发送数据的 ack 回包只要没满足上面条件中的一条,发送方一直在囤积数据,直到满足上面的发送条件。另外,Nagle 算法默认是打开的,如果对于一些需要小数据包交互的场景的程序,比如,telnet 或 ssh 这样的交互性比较强的程序,则需要关闭 Nagle 算法。可以在 Socket 设置 TCP_NODELAY 选项来关闭这个算法

推荐阅读