TCP系列31—窗口管理&流控—5、TCP流控与滑窗
一、TCP流控
之前我们介绍过TCP是基于窗口的流量控制,在TCP的发送端会维持一个发送窗口,我们假设发送窗口的大小为N比特,网络环回时延为RTT,那么在网络状况良好没有发生拥塞的情况下,发送端每个RTT就可以发送N比特的数据,发送端的速率应该与N/RTT成正比,因此通过改变发送窗口的大小就可以控制发送端的发送速率,那么接收端就可以通过控制发送端发送窗口的大小来控制发送速率。这样接收端需要有一种方式通告发送端接收端期望的发送窗口大小,这种方式就叫做窗口通告(window advertisement),或者叫做窗口更新(window update)。另外窗口更新(window update)一般特指窗口大小发生变化的时候通告新窗口的事件。TCP是双向通信,因此TCP两端都会同时维护一个发送窗和一个接收窗。
二、TCP窗口信息交互
如下图所示,在client发送至server方向(C->S)的数据传输用下方的浅色箭头表示,而server发送至client方向(S->C)的数据传输用上方的深色箭头表示。图中深色和浅色字段也分别标示了不同数据传输方向的信息。与C->S方向浅色表示的数据传输相对应的,在client端会维护一个发送窗口,在server端会维护一个接收窗口,client端发送窗口的滑窗操作需要依靠S->C方向数据段的ACK和WIN信息来更新(在图中同样用浅色标示了出来),server端接收窗口的滑窗操作则需要C->S方向数据段中Seq和Data信息来更新。与S->C方向深色表示的数据传输相对应的,在server端会维护一个发送窗口,在client端会维护一个接收窗口,server端发送窗口的滑窗操作需要依靠C->S方向数据段的ACK和WIN信息来更新(在图中用深色标示了出来),client端接收窗口的滑窗操作则需要S->C方向数据段中Seq和Data信息来更新。这样可以看到一个TCP连接共有四个窗口,TCP会用窗口结构(window structures)来维护这些相关信息。
除了连接建立过程中的TCP报文外,每个TCP报文都会带有一个有效的系列号Seq、确认号Ack Number、窗口大小Window size字段。其中系列号和确认号我们之前已经接触介绍过多次。而窗口大小Window size字段则表示接收端还有多少预留空间来接收数据,即接收端愿意接收的最大系列号为(Ack number + Window size)。一般来说接受端的应用层在接收到TCP数据后都会立即读取出来,这样实际上通过Window size通告的预留空间并不会发生太大变化,但是如果接收端应用层没有及时读取新接收到的TCP数据的话,这些数据就会在缓存空间中积压,进而Window size慢慢变小(实际上linux会自动调整接收缓存和发送缓存,这里暂时按照固定缓存大小的情况来说明,后续文章在介绍缓存自动调整),如果应用层一直没有读取数据,那么最终没有缓存空间后,Window size就会变为0,发送端也就不能继续发送新数据了。Window Size字段最大为16bit,但是通过TCP的WIndow Scale选项可以扩大到大约1GB大小(请参考前面文章中关于WSOPT选项的介绍)。

三、发送端滑窗
我们首先来看一下发送窗口结构(send window structure),如下图所示在发送端的系列号空间中,可以划分为四部分,分别是已经发送并且已经收到ACK确认包的数据,已经发送但是还没有收到ACK确认包的数据,还未发送但是对端可以接收的数据,还未发送的对端还未准备接收的数据。其中SND.UNA、SND.NXT、(SND.UNA+SND.WND)三个构成了这四部分的边界。而我们说的发送窗则是中间两部分数据,即SND.UNA构成发送窗口的左边沿,(SND.UNA+SND.WND)构成发送窗的右边沿。左右边沿之间的数据也叫做Offered Window,SND.NXT和(SND.UNA+SND.WND)之间的数据也叫做Usable Window。
当接收端回复ACK确认包并确认新数据的时候(同时带有Window size字段),发送窗口左边沿就会向右移动,右边沿一般也会向右滑动,但是也可能保持位置不变甚至向左移动,我们一般用Closes、Shrinks、Opens等来描述窗口边沿的变化情况
Closes:当发送窗口的左边沿向右移动的时候,我们一般称呼为窗口关闭。这一般发生在对端ACK确认了新数据,但是整个window size大小变小。
Shrinks:当发送窗的右边向左移动的时候我们称呼为窗口收缩。RFC1122强烈建议避免这种情况,但是接收端TCP要等处理这种情况。
Opens:当发送窗口的右边沿向右移动的时候,我们称呼为窗口打开。这一般发生在应用层读取了新数据或者缓存自动调整的时候,对端TCP可以接收更多的新数据场景。
因为ACK是累积确认的,所以发送窗口的左边沿不会向左移动。一个常见的情况是ACK number确认了新数据,而Window size大小并没有变化(原因是应用层即使读取了TCP接收的数据或者缓存自动调整),这时候我们就说向前推进(advance)了这个发送窗口,或者说这个发送窗向前滑动(slide forward)了。当ACK number确认了新数据,但是Window size慢慢变小,最后变为0的时候,这种窗口称呼为zero window,这时候发送端就不能发送任何的数据了,需要定时探测对端的窗口大小,这种场景我们后面会进行进一步的介绍。

四、接收端滑窗
接着我们看一下接收窗口结构(receive window structure),如下图所示接收窗口要简单一些,主要分为三个部分,已经接收的系列号连续的并且回复了ACK报文的数据,未接收的但是正准备接收的数据或者是已经接收的落在了接收窗口内部但是系列号不连续的数据,还未准备接收的数据。其中RCV.NXT指向了接收窗的左边沿,(RCV.NXT+RCV.WND)指向了接收窗的右边沿。RCV.WND指定了接收窗口的大小。通过这个接收窗口结构可以让接收端避免接收到重复的报文。按照协议超过(RCV.NXT+RCV.WND)的数据是可以丢弃的,但是在后面文章中我们将会看到linux实现一般并不会直接丢掉窗口右边的报文。

五、wireshark示例
在linux内部会维护几个与发送窗口相关的变量如下:snd_una、snd_wnd、snd_nxt。与接收窗口相关的变量如下rcv_nxt、rcv_wnd。另外选择窗口的时候还会涉及一个rcv_mss的变量,这个变量是linux对对端MSS的一个保守估计值,在讲解延迟ACK的时候我们已经介绍过这个变量是如何初始化和调整的,这里不再介绍。下面我们通过一个TCP通信实例来看一下server端这几个变量的变化,在测试过程中,我们通过SO_RCVBUF选项设置server端为3000,client端为3500。并把tcp_adv_win_scale的值由默认的1改为2。SO_RCVBUF选项与Window size的关系我们后面内容会介绍。
1、server端收到No3这个数据包之后,即在三次握手之后,server端这几个变量分别为snd_una=1065017116、 snd_wnd=5250、 snd_nxt=1065017116、 rcv_nxt=188998934、 rcv_wnd=4500、 rcv_mss=536
2、server端收到No4回复No5确认包之后,server端这几个变量分别为snd_una=1065017116、 snd_wnd=5250、 snd_nxt=1065017116、 rcv_nxt=188999034、 rcv_wnd=4400、 rcv_mss=536,实际上这几个变量是在收到No4变量的时候更新的,并不是在发出No5之后。
3、server端发出No6数据包之后,server端这几个变量分别为snd_una=1065017116、 snd_wnd=5250、 snd_nxt=1065017316、 rcv_nxt=188999034、 rcv_wnd=4400、 rcv_mss=536
4、server端收到No7确认包之后,server端这几个变量分别为snd_una=1065017316、 snd_wnd=5050、 snd_nxt=1065017316、 rcv_nxt=188999034、 rcv_wnd=4400、 rcv_mss=536
5、server端收到No8数据包回复No9确认包之后,server端这几个变量分别为snd_una=1065017316、 snd_wnd=5050、 snd_nxt=1065017316、 rcv_nxt=189001185、 rcv_wnd=2249、 rcv_mss=2151
6、接着server端应用层把接收到的2251bytes全部读取出来
7、server端接着发出No11报文,在应用层把缓存的TCP数据读取出来后,此时接收缓存对应的最大接收窗口已经可以到4500bytes,但是linux在处理的时候会取rcv_mss的整数倍,因此在No11报文中可以看到Window size=4502。

补充说明:
1、Window size的选择流程比较复杂,并不是都选为rcv_mss的整数倍,示例中因为Window scale选项为0,且满足一些条件所以才会把Window size选择为4302。详细的流程可以参考代码tcp_select_window。
TCP系列31—窗口管理&流控—5、TCP流控与滑窗的更多相关文章
- TCP系列27—窗口管理&流控—1、概述
在前面的内容中我们依次介绍了TCP的连接建立和终止过程和TCP的各种重传方式.接着我们在这部分首先关注交互式应用TCP连接相关内容如延迟ACK.Nagle算法.Cork算法等,接着我们引入流控机制(f ...
- TCP系列33—窗口管理&流控—7、Silly Window Syndrome(SWS)
一.SWS介绍 前面我们已经通过示例看到如果接收端的应用层一直没有读取数据,那么window size就会慢慢变小最终可能变为0,此时我们假设一种场景,如果应用层读取少量数据(比如十几bytes),接 ...
- TCP系列34—窗口管理&流控—8、缓存自动调整
一.概述 我们之前介绍过一种具有大的带宽时延乘积(band-delay product.BDP)的网络,这种网络称为长肥网络(LongFatNetwork,即LFN).我们想象一种简单的场景,假设发送 ...
- TCP系列36—窗口管理&流控—10、linux下的异常报文系列接收
在这篇文章中我们看一下server端在接收到异常数据系列时的处理,主要目的是通过wireshark示例对这些异常数据系列的处理有一个直观的认识,感兴趣的自行阅读相关代码和协议,这里不再进行详细介绍 在 ...
- TCP系列35—窗口管理&流控—9、紧急机制
一.概述 我们在最开始介绍TCP头结构的时候,里面有个URG的标志位,还有一个Urgent Pointer的16bits字段.当URG标志位有效的时候,Urgent Poinert用来指示紧急数据的相 ...
- TCP系列32—窗口管理&流控—6、TCP zero windows和persist timer
一.简介 我们之前介绍过,TCP报文中的window size表示发出这个报文的一端准备多少bytes的数据,当TCP的一端一直接收数据,但是应用层没有及时读取的话,数据一直在TCP模块中缓存,最终受 ...
- TCP系列30—窗口管理&流控—4、Cork算法
一.Cork算法概述 Cork算法与Nagle算法类似,也有人把Cork算法称呼为super-Nagle.Nagle算法提出的背景是网络因为大量小包小包而导致利用率低下产生网络拥塞,网络发生拥塞的时候 ...
- TCP系列29—窗口管理&流控—3、Nagle算法
一.Nagle算法概述 之前我们介绍过,有一些交互式应用会传递大量的小包(称呼为tinygrams),这些小包的负载可能只有几个bytes,但是TCP和IP的基本头就有40bytes,如果大量传递这种 ...
- TCP系列28—窗口管理&流控—2、延迟ACK(Delayed Acknowledgments)
一.简介 之前的内容中我们多次提到延迟ACK(Delayed Ack),延迟ACK是在RFC1122协议中定义的,协议指出,一个TCP实现应该实现延迟ACK,但是ACK不能被过度延迟,协议给出延迟AC ...
随机推荐
- opencv3 学习四 - 图像减色
程序如下 #include "opencv2/opencv.hpp" using namespace cv; int main() { // 灰度图 Mat original = ...
- 企业网站被黑 dedecms漏洞修复办法
前段时间网站被黑了,从百度打开网站直接被劫持跳转到了彩票,du博网站上去,网站的首页index.html文件也被篡改成一些什么北京sai车,pk10,一些cai票的关键词内容,搞得网站根本无法正常浏览 ...
- st link 连接问题ST LINK is not in the DFU mode plesse restart it
原因:插上st link后做了一些操作才点击升级.如点击了连接stlink,如下图等: 解决办法: 1. 拔掉stlink 2. 插上stlink 3. 不要点其他的,直接点击ST-LINK-> ...
- P2257 YY的GCD
P2257 YY的GCD 题目描述 神犇YY虐完数论后给傻×kAc出了一题 给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对 k ...
- 小程序开发-11-Promise正确用法与函数签名设计技巧
配置taBar "tabBar": { "selectedColor": "#000000", "backgroundColor& ...
- Python3爬虫(十五) 代理
Infi-chu: http://www.cnblogs.com/Infi-chu/ 一.设置代理 1.urllib #HTTP代理类型 from urllib.error import URLErr ...
- Go Web Gin EasyUI 框架
项目结构 第三方: 1.gin微服务框架 2.EasyUI框架
- 使用putty远程登录Ubuntu时,报Network error:Connection refused错误及解决
putty远程登录Ubuntu,弹出Network error:Connection refused的错误提示框,就是因为Ubuuntu没有安装ssh服务. 执行命令: sudo apt instal ...
- 【LG1527】[国家集训队]矩阵乘法
[LG1527][国家集训队]矩阵乘法 题面 洛谷 题解 我也不知道为什么取个这样的名字... 其实就是区间\(kth\)扩展到二维 还是用整体二分搞啦,把树状数组换成二维的 其他的基本没有什么差别 ...
- AFD运维
1.afd 网址:https://www.dwd.de/AFD/html-en/contents.html 2.问题:拷贝了一个主机A配置后(HOST_CONFIG主机项),修改为另一个主机B配置:然 ...