您的位置:首页 > 理论基础 > 计算机网络

TCP-流量控制

2017-03-10 13:14 211 查看
所谓的“流量控制”,就是让发送方的发送速率不要太快,要让接受方来的及接收。这是一种对于端的控制,不像拥塞控制,是对网络状况的控制。

那么,TCP是怎么实现流量控制的了?这个可以从成块数据(大分组)、交互数据流(小分组)两种数据流情况来详细讨论。

一、成块数据

对于成块数据,一般采用滑动窗口实现流量控制。

滑动窗口

滑动窗口,也就是接收方来控制发送方,接收方告诉发送方,自己最多可以接受多少数据,然后发送方根据这个窗口值发送数据,发送窗口不能超过接受窗口的大小。

值得注意的是,TCP的窗口单位是字节,不是报文段。下面看一个实际例子。



我们假设A向B发送数据。在连接建立时,B告诉了A:“我的接收窗口是 rwnd = 400 ”(这里的 rwnd 表示 receiver window) 。因此,发送方的发送窗口不能超过接收方给出的接收窗口的数值。TCP连接建立时的窗口协商过程在图中没有显示出来。再设每一个报文段为100字节长,而数据报文段序号的初始值设为1。大写ACK表示首部中的确认位ACK,小写ack表示确认字段的值。

从图中可以看出,B进行了三次流量控制。第一次把窗口减少到 rwnd = 300 ,第二次又减到了 rwnd = 100 ,最后减到 rwnd = 0 ,即不允许发送方再发送数据了。这种使发送方暂停发送的状态将持续到主机B重新发出一个新的窗口值为止。

我们考虑一种特殊情况,如果B在向A发送了零窗口报文段后不久,B的接收缓存又有了一些存储空间,于是B向A发送了一个rwnd=400的报文段,然而这个报文段在传送过程中丢失了,A就一直等待B发送非零窗口的报文通知,而B一直等待A发送数据,如果没有任何措施的话,这话死锁的局面会一直延续下去。

为了解决这个问题,TCP为每一个连接设有一个持续计时器(也叫坚持定时器)。只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口控测报文段(携1字节的数据),对方在收到探测报文段后,在对该报文段的确认洪给出现在的窗口值,如果窗口值仍未零,则收到这个报文段的一方就重新设置持续计时器,如果窗口不为零,那么死锁的僵局就被打破了。

糊涂窗口综合症

设想一种情况,TCP接收方的缓存已满,而应用进程一次只从接收缓存中读取1字节(这样就使接收缓存空间仅腾出1字节),然后向发送方发送确认,并把窗口设置为1个字节(但发送的数据报为40字节长)。接收,发送方又发来1个字节的数据(发送方的IP数据报是41字节)。接收方发回确认,仍然将窗口设置为1个字节。这样,网络的效率很低。要解决这个问题,可让接收方等待一段时间,或者等到接收方缓存已有一半空闲的空间。只要出现这两种情况之一,接收方就发回确认报文,并向发送方通知当前的窗口大小。此外,发送方也不要发送太小的报文段,而是把数据报积累成足够大的报文段,或达到接收方缓存的空间的一半大小时再发送给接收端。

二、交互数据

对于交互数据流,TCP利用Nagle算法和捎带ACK来实现流量的控制。

Nagle算法

简单点说,就是在一个小分组被确认后,才发送下一个小分组。

具体算法如下:发送方发送数据时,先把第一个小分组先发送出去,然后把后面到达的数据分组都缓存起来。当发送方发送方收到第一个分组的确认后,再把发送缓冲区中的所有数据组装成一个报文段发送出去,同时继续对后续到达的数据进行缓存。只有收到前一个报文段的确认后才继续发送下一个报文段。

Nagle算法还规定,当到达数据已达到发送窗口大小的一半或已达到报文段的最大长度时,就立即发送一个报文段。

ACK延滞算法

该算法使得TCP在接收到数据后不利己发送ACK,而是等待一小段时间(典型值为50~200ms),然后才发送ACK。TCP期待这段时间内自身有数据发回对端,被滞留的ACK就可以由这些数据捎带着,从而省掉一个TCP分节。

不适合使用这两个算法的情况

对于其服务器不存在相反方向产生数据以便携带ACK的客户来说,ACK延滞算法存在问题。这些客户会感觉到明显的延迟,因为客户TCP要等到服务器的ACK延滞定时器超时才继续给服务器发送数据。这些客户需要一种禁止Nagle算法的方法,TCP_NODELAY就是起到这个作用。

另一类不适合使用Nagle算法和TCP的ACK延滞算法的算法的客户是以若干小片数据向服务器发送单个逻辑请求的客户。也就是这个请求只有一个,你如果将其分为两次发,那么服务器收到前一部分时,啥也做不了,必须等到后一部本也受到,而后一部分有一定延迟才收到,这样就没必要使用这两个算法。那么我们可以:1)禁掉TCP_NODELAY;2)把把这一个完整请求都复制到单个缓冲区中,然后对该缓冲区调用一次write;3)使用writev而不是使用两次write.

三、参考:

《计算机网络 谢希仁》

《unix 网络编程 卷一》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  tcp流量控制