一条TCP连接每一侧主机都应为该连接设置接收缓存,当TCP收到正确、按序的字节后,它将数据放入接收缓存。相关的应用进程从该缓存中读取数据,应注意,读取缓存可能并不是数据一到达就立即读取,因为接收方应用可能正忙于其他任务。这时问题就产生了,如果接收方读取太慢,发送发发送太快、太多,那么接收缓存会发生溢出。
流量控制:用来消除发送方使接收方缓存溢出的可能性。流量控制是一个速度匹配服务,即发送方的发送速率与接收方应用程序的读取速率相匹配。
尽管流量控制和拥塞控制都是对发送方的抑制,但它们是针对完全不同的原因而采取的措施。
流量控制是因为发送速率与读取速率不匹配。
拥塞控制是因为IP网络的拥塞。
TCP让发送发维护一个接收窗口的变量来提供流量控制。
接收窗口:接收方还有多少可用的缓存空间。
因为TCP是全双工通信,接收方也会维护一个接收窗口。
具体流量控制如下:
定义三个变量,分别是:
RcvBuffer:接收缓存的大小
LastByteRead:接收方的应用进程从缓存中读取的数据流的最后一个字节的编号。
LastByteRcvd:到达接收方且放入接收方缓存中的数据流的最后一个字节的编号。
TCP为了不让已分配的缓存溢出,必须成立以下不等式:
LastByteRcvd - LastByteRead <= RcvBuffer
两者的差为还在缓存中的字节数,因为这个不等式很好理解,缓存中还存在的字节数必须小于等于接收缓存的大小。
你会发现,上面并未提到接收窗口,既然是通过接收窗口来实现流量控制,那我们下面就需要用到接收窗口。
接收窗口用rwd表示,上面提过还在缓存中的字节数,那么接收窗口就是我们还可以放多少字节到接收缓存中,因此:
rwd = RcvBuffer - [LastByteRcvd - LastByteRead]
该空间是随时间变化的,因此rwd也是动态的。(当然是变化的,因为接收方的应用进程会从缓存读取数据嘛!)通过rwd我们就实现了流量控制,即发送方可以根据rwd的大小来发送!
后话:rwd与LastByteRcvd - LastByteRead的关系,为了保证接收缓存不会溢出,因此TCP连接的整个生命周期须保证:
LastByteRcvd - LastByteRead <= rwd



