众所周知,TCP是有缓冲区的,比如接收缓冲区用于存放已经到达但是还没有被应用程序及时处理的数据。但是任何缓冲区都是有一定大小的,如果发送方发送数据过快,而接收方处理数据过慢,就会导致接收方的接收缓冲区数据量不断累积最终塞满缓冲区。随后如果再有数据到达就只有一个结果,数据被丢掉
为了解决这一问题,TCP引入了流量控制功能,所谓流量控制,就是让发送方发送速率不要太快,要让接收方来得及处理。通过滑动窗口机制,可以很容易实现流量控制
序列号
在介绍流量控制之前,首先需要明确一个概念,就是数据序列号。它的作用是标识数据,数据的每一个字节都有与之对应的序列号,并且在双方通信的过程中序列号是连续的。通信双方就是通过序列号来控制数据的发送和接收
以客户端A和服务器B通信为例,客户端A发送一个包含100字节数据的报文段,其中数据的第一个字节的序列号为200,那么可以得知这段数据的序列号范围是[200 : 299],服务器接收到这段数据后回应客户端一个应答报文段,该报文段中包含了服务器希望下次接受的数据第一个字节的序列号,即300.
通过这样的一来一往,服务器接收到序列号为[200:299]的这段数据,并且告知客户端自己接下来需要接收序列号从300开始的数据。而客户端知道服务器已经接收到[200:299]这段数据,并且准备发送序列号从300开始的数据。
如前所述,TCP内部设有发送缓冲区和接收缓冲区,为了将事情简化,下面仅考虑客户端的发送缓冲区以及服务器的接收缓冲区。同时,与发送缓冲区对应的是发送窗口,与接收缓冲区对应的是接收窗口。这两个滑动窗口在三次握手建立连接后被创建,起点是对方的起始序列号(由SYN同步位被标记为1的报文段确定)。
此外,除了起始序列号,三次握手的过程中还各自通知了窗口大小。如服务器告诉客户端窗口大小为100,则客户端初始的滑动窗口大小就为100
100是服务器目前可以接收的序列号个数,也即字节个数
在平时的网络编程中,应用程序使用send/write等api将数据发送给对端,实际上仅仅是将数据复制到自己的TCP发送缓冲区就返回了,剩下的事情TCP协议栈会自己完成,在合适的时间将数据发送出去。这里合适的时间就是根据发送窗口判断的。
数据发送时滑动窗口的变化
从发送缓冲区的视角观察,滑动窗口位于发送缓冲区上,覆盖的区域表示能被立即发送的数据区域或者已经发送但是没有收到接收方应答的数据
接收方发送的报文段中包含了发送方应该设置的窗口大小,即接收方提供的窗口。图片中此时滑动窗口覆盖了[4:9]字节的区域,表明接收方已经确认了包括第3个字节以内的所有数