链接:https://www.zhihu.com/question/32255109/answer/68558623
来源:知乎
著作权归作者所有,转载请联系作者获得授权。
滑动窗口协议是 传输层进行流控的一种措施, 接收方通过通告发送方自己的窗口大小,从而控制发送方的发送速度,从而达到防止发送方发送速度过快而导致自己被淹没的目的。
对ACK的再认识,ack通常被理解为收到数据后给出的一个确认ACK,ACK包含两个非常重要的信息:
一是期望接收到的下一字节的序号n,该n代表接收方已经接收到了前n-1字节数据,此时如果接收方收到第n+1字节数据而不是第n字节数据,接收方是不会发送序号为n+2的ACK的。举个例子,假如接收端收到1-1024字节,它会发送一个确认号为1025的ACK,但是接下来收到的是2049-3072,它是不会发送确认号为3072的ACK,而依旧发送1025的ACK。
二是当前的窗口大小m,如此发送方在接收到ACK包含的这两个数据后就可以计算出还可以发送多少字节的数据给对方,假定当前发送方已发送到第x字节,则可以发送的字节数就是y=m-(x-n).这就是滑动窗口控制流量的基本原理
重点:发送方根据收到ACK当中的期望收到的下一个字节的序号n以及窗口m,还有当前已经发送的字节序号x,算出还可以发送的字节数。
发送端窗口的第一个字节序号一定是ACK中期望收到的下一个字节序号,比如下图:
<img src="https://i-blog.csdnimg.cn/blog_migrate/898ff5eb1a93867f39eeffa69de763ec.png" data-rawwidth="667" data-rawheight="216" class="origin_image zh-lightbox-thumb" width="667" data-original="https://pic1.zhimg.com/9c21786770459afa47bfa2e4606cc454_r.png">上图52 53 54 55 字节都是可以新发送的字节序 上图52 53 54 55 字节都是可以新发送的字节序
接受端窗口的第一个字节序之前一定是已经完全接收的,后面窗口里面的数据都是希望接受的,窗口后面的数据都是不希望接受的。
http://blog.chinaunix.net/uid-20778955-id-539945.html
http://www.netis.com.cn/flows/2012/08/tcp-%E6%BB%91%E
5%8A%A8%E7%AA%97%E5%8F%A3%E7%9A%84%E7%AE%80%E4%BB%8B/
TCP的滑动窗口分为接收窗口和发送窗口
不分析这两种窗口就讨论是不妥当的。
TCP的滑动窗口主要有两个作用,一是提供TCP的可靠性,二是提供TCP的流控特性。同时滑动窗口机制还体现了TCP面向字节流的设计思路。TCP 段中窗口的相关字段。
<img src="https://i-blog.csdnimg.cn/blog_migrate/f0b400699a9b5d73131db5c6aca28876.png" data-rawwidth="620" data-rawheight="197" class="origin_image zh-lightbox-thumb" width="620" data-original="https://pic2.zhimg.com/d6b970fb6d44aafeeec4a4c9d61a9225_r.png">
TCP的Window是一个16bit位字段,它代表的是窗口的字节容量,也就是TCP的标准窗口最大为2^16-1=65535个字节。
另外在TCP的选项字段中还包含了一个TCP窗口扩大因子,option-kind为3,option-length为3个字节,option-data取值范围0-14。窗口扩大因子用来扩大TCP窗口,可把原来16bit的窗口,扩大为31bit。
滑动窗口基本原理
1)对于TCP会话的发送方,任何时候在其发送缓存内的数据都可以分为4类,“已经发送并得到对端ACK的”,“已经发送但还未收到对端ACK的”,“未发送但对端允许发送的”,“未发送且对端不允许发送”。“已经发送但还未收到对端ACK的”和“未发送但对端允许发送的”这两部分数据称之为发送窗口。
<img src="https://i-blog.csdnimg.cn/blog_migrate/92a7b7d72597498bccf2f75ba60b353e.png" data-rawwidth="664" data-rawheight="177" class="origin_image zh-lightbox-thumb" width="664" data-original="https://pic1.zhimg.com/a1d5c050ad957880094a5f003b1ccd24_r.png">当收到接收方新的ACK对于发送窗口中后续字节的确认是,窗口滑动,滑动原理如下图。当收到接收方新的ACK对于发送窗口中后续字节的确认是,窗口滑动,滑动原理如下图。
<img src="https://i-blog.csdnimg.cn/blog_migrate/898ff5eb1a93867f39eeffa69de763ec.png" data-rawwidth="667" data-rawheight="216" class="origin_image zh-lightbox-thumb" width="667" data-original="https://pic1.zhimg.com/9c21786770459afa47bfa2e4606cc454_r.png">
当收到ACK=36时窗口滑动。
2)对于TCP的接收方,在某一时刻在它的接收缓存内存在3种。“已接收”,“未接收准备接收”,“未接收并未准备接收”(由于ACK直接由TCP协议栈回复,默认无应用延迟,不存在“已接收未回复ACK”)。其中“未接收准备接收”称之为接收窗口。
发送窗口与接收窗口关系
TCP是双工的协议,会话的双方都可以同时接收、发送数据。TCP会话的双方都各自维护一个“发送窗口”和一个“接收窗口”。其中各自的“接收窗口”大小取决于应用、系统、硬件的限制(TCP传输速率不能大于应用的数据处理速率)。各自的“发送窗口”则要求取决于对端通告的“接收窗口”,要求相同。
<img src="https://i-blog.csdnimg.cn/blog_migrate/7e234ff1773370c9b2449b82da78a5d8.png" data-rawwidth="675" data-rawheight="527" class="origin_image zh-lightbox-thumb" width="675" data-original="https://pic4.zhimg.com/c798dd393fcf7c03b1db78f5bcf0304b_r.png">滑动窗口实现面向流的可靠性
1)最基本的传输可靠性来源于“确认重传”机制。
2)TCP的滑动窗口的可靠性也是建立在“确认重传”基础上的。
3)发送窗口只有收到对端对于本段发送窗口内字节的ACK确认,才会移动发送窗口的左边界。
4)接收窗口只有在前面所有的段都确认的情况下才会移动左边界。当在前面还有字节未接收但收到后面字节的情况下,窗口不会移动,并不对后续字节确认。以此确保对端会对这些数据重传。
滑动窗口的流控特性
TCP的滑动窗口是动态的,我们可以想象成小学常见的一个数学题,一个水池,体积V,每小时进水量V1,出水量V2。当水池满了就不允许再注入了,如果有个液压系统控制水池大小,那么就可以控制水的注入速率和量。这样的水池就类似TCP的窗口。应用根据自身的处理能力变化,通过本端TCP接收窗口大小控制来对对对端的发送窗口流量限制。
应用程序在需要(如内存不足)时,通过API通知TCP协议栈缩小TCP的接收窗口。然后TCP协议栈在下个段发送时包含新的窗口大小通知给对端,对端按通知的窗口来改变发送窗口,以此达到减缓发送速率的目的。