前言
TCP连接的接收方会设置一个 接收缓存 ,当TCP连接收到正确、按序的字节后,就将数据放入接收缓存
这时,如果接收方读取数据相对较缓慢,而发送方发送太多、太快,就会导致接收方的接收缓存溢出
因此,TCP提供一个流量控制控制服务,以消除发送方使接收方缓存溢出的可能性
流量控制因此是一个速度匹配服务,即发送发的发送速率和接收方应用程序的读取速率相匹配
接收窗口
TCP通过让发送方维护一个称为接收窗口的变量来提供流量控制
接收窗口用于给发送方一个提示:该接收方还有多少可用的缓存空间
假设情况
假设A向B发送一个文件,设B的接收缓存大小为 RcvBuffer
B的应用进程不时地从该缓存中读取数据
我们定义以下变量:
- LastByteRead:主机B上的应用进程从缓存读出的数据流的最后一个字节的编号
- LastByteRcvd:从网络中到达的并且已放入主机B接收缓存中的数据流的最后一个字节的编号
为了不使缓存溢出,我们需要满足:
LastByteRcvd - LastByteRead <= RcvBuffer
接收窗口的大小,是动态的
rwnd = RcvBuffer - [ LastByteRcvd - LastByteRead]
综上,我们只要控制未确认的数据量在rwnd以内即可(就是主机A已经发送到TCP连接中,但未被确认的数据量小于接收窗口的大小)
[LastByteRcvd - LastByteRead] <= rwnd
如果在某一时刻,rwnd=0,即接收缓存已经满时,B告诉A已经满了,但是如果一段时间后B读取完接收缓存的数据后,接收缓存有了新的空间,但是A不会接收到这个通知!
因为事实上,TCP仅当在它有数据或有要确认要发时才会发送报文段给主机A,这样的话A不可能知道主机B的接收缓存已经有新的空间
这时就会造成阻塞: A在等B的新空间,B在等A发新数据
解决方法:
-
TCP为每一个连接设有一个持续计时器(persistence timer),只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器
-
TCP要求:当主机B的接收窗口为0时,若持续计时器设置的时间到期,主机A就继续发送只有一个字节数据的报文段,这些报文段会被接收方确认,最终缓存开始清空,并且确认报文里将包含一个非0的rwnd值