[TCP专题]TCP的流量控制

        说到TCP的流量控制,它其实应该是属于TCP可靠性保障的一环,只不过其中涉及的知识点,值得我们单独拉出来好好的研究一下。

滑动窗口

        而要谈及流量控制,就不得不说一下TCP头部中的一个变量,那就是“窗口值”了。这个窗口值应该算是TCP实现流控的一个核心参数。

        我们知道,TCP的传输为了保证可靠性,要求每发一个数据,就要得到一次确认应答。只有收到了之前数据包的确认之后,才会发送之后的数据包。很明显,这样的传输效率并不高。如果,你发送了一个信息到对端,但是对方此时可能并没能及时处理这个信息,那你就需要一直干等。这样将导致数据包的往返时间越长,通信的效率就会越低。

        所以,何不趁多方忙别的时候,自己多发几个数据包呢?为此,我们专门引入了一个变量,那就是窗口。这个窗口的大小是可以指定的,窗口大小指的就是无需等待确认应答,而可以继续发送数据包的最大值。

        窗口的大小,其实体现的就是缓存区的大小。我们前面说过,TCP双方都将为这个TCP连接建立缓存区域。发送方在发送数据的时候,在没有接收到对方的确认报文之前,发送的数据需要暂时存放在缓存区。而接受方,在接收到数据来不及处理,也需要暂存在缓存区。所以,窗口的大小需要充分考虑缓存区的大小才行。

        这里我们给一个场景,假设窗口的大小是3个TCP报文段的大小。那其效果就是,发送方(我们以客户端作为发送方)可以一次性的发送三个TCP报文段,之后等待对方的确认。接收方(假定服务器方)理应针对这三个报文段进行确认,但实际上,中间的确认报文段就算丢失,也问题不大,不会触发重传,因为之前我们就说过,TCP是累计确认,只要收到最后的确认报文就相当于将前面的内容都确认了。

        其实窗口值的用法是比较好理解的,主要是,这个参数是如何进行流控的?前面说了,这个窗口值的大小反应的是缓存区域的大小,所以这个参数并不是一成不变的。

        TCP要求发送方依据接收窗口(receive window)--- rwnd来控制数据的发送量。这个接收窗口,其实反应的就是接受方此时缓存空间可用的大小,通过接收方发送数据包中的窗口值这个变量来携带。当然,因为TCP本身是一个全双工的通信协议,所以,通信双方都各自需要维护一个接收窗口。

        我们现在假设客户端给服务器发送信息(我们只看一边),假设服务器为连接分配的缓存空间用RcvBuffer来表示其大小。服务器上的进程会从这个缓存区域中读取数据。从网络中到达并放入服务器缓存空间中的数据量减去服务器进程已经读取的数据量必须要小于我们整个的RcvBuffer,才能保证缓存区不溢出。而RcvBuffer减去他们之间的差值便是rwnd。 --- 这个空间就是随时间变化的,所以,rwnd也是随时间变化的。 

        服务器就是将当前的rwnd值放入发送给客户端的报文窗口字段,来通知客户端他在该连接中还有多少缓存空间可用。(开始时,rwnd == RcvBuffer)

        而客户端需要保证的就是发送的字节最大序号减去本端收到的最后确认的序号值小于rwnd。(其实就是发出还没有确认的数据量)这样才能保证服务器接收数据时不会溢出。

        也正是这样可变的窗口流控机制,我们称之为滑动窗口机制。

窗口关闭

        既然窗口值是接受端根据自己缓存空间的剩余量来决定的一个动态值,那这个剩余量就有归0的可能性。也就是代表此时接收方所有缓存空间均已占用并且没能及时处理里面的资源。所以,当接受方反馈窗口值为0的数据报文段,那其实就是在通知发送方,别再发了,处理不过来了。这种情况就是所谓的窗口关闭。

        当然,这种机制可能存在一定的风险。接受方是通过确认ACK报文来通知发送方自己的窗口大小的。理论上,如果接受方将自己缓存里的数据清空后,将反馈一个窗口值非0的报文来通知发送方,可以继续发送数据了。但如果这个非0的ACK报文在传输过程中丢失了呢?

        确认报文丢失了也不会触发重传机制,所以,客户端依然处于窗口关闭状态,所以不会发送数据,等待服务器响应。而服务器也会等待对方发送数据。所以,这样将进入到一个死锁的状态。

        不过,这里的应对方法也是很简单。一端在遇到这种0窗口的情况,并不会什么都不做(比如我们给定场景中的客户端),他会定时的发送一个只包含一个字节的窗口探测报文(window probe)。这些报文需要被接受方所确认,确认报文段中将包含当前的窗口值。如果当前的窗口值依然为0,则发送方会周期时间后继续发送探测报文,直到窗口值非0。则可以继续发送数据,即打破了死锁现象。

小窗口处理 

        在看TCP流控相关的文章的时候,看到了这样的一种特殊情况,很有意思。如果接受方需要处理的数据比较多的情况下,就会导致窗口值越来越小。到最后,如果接受方只能腾出几个字节的窗口,而发送方将只能发送几个字节。

        我们知道,光我们协议封装的头部,都需要占用几十个字节(比如TCP+IP头部最短就有40个字节),如果只传输几个字节的数据的话,那这个传输的经济性,则将大打折扣。

        所以,在这种情况下,应该避免接受方通告小的窗口,而发送方,也应避免发送小的数据。

        接收方一般采取的策略是设定一个窗口通告的最小值。这个最小值通常选择MSS或者1/2缓存空间这两个值中较小者。当窗口值小于其二者较小者的值时,将通告窗口值为0。直到窗口大小突破那个最小值之后,再打开窗口。

        而发送方一般的策略是启用延时处理,只有在满足以下两个条件中任意一个时,才会发送数据,否则,将一直囤积数据,直到满足任一条件为止。

  • 条件一:要等到窗口大小 >= MSS 并且 数据大小 >= MSS;
  • 条件二:收到之前发送数据的ack回包;

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

临界~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值