才子佳人博客

我的故事我讲述

详解TCP滑动窗口和流控机制
 
来源:www.jianshu.com  编辑:xjh  2017-10-25

TCP的滑动窗口是一个很重要的概念,也是比较难的一个知识点。下面就大概介绍下TCP滑动窗口为什么出现?它是如何实现流量控制的?

什么是TCP窗口?

首先,要理解,client和server各自协议栈都有自己的buffer,应用层读写数据的源都是协议栈buffer。以Server接收端为例,应用程序调用read()时,会从buffer里移走数据到用户程序空间,应用程序读的速度越快,那么buffer里的内容消费的越快,buffer也会越空。那么TCP就可以告诉发送端client,我现在很闲,你可以发送更多的数据来。"更多"是多少?这就是窗口,窗口就是量化接收端当前能处理数据的能力。或者说,窗口值明确指出了允许对方发送的数据量,是接收方让发送方设置其发送窗口的依据。

TCP窗口是如何工作的?

client和server端建立连接后,client会告诉server,自己的"接收窗口"大小(自己能接收多少的数据,受上面所说的buffer影响),server端接收到client的"接收窗口"大小,就会变成server端自己的"发送窗口"大小。同样,server端告诉client自己的"接收窗口"大小,就会变成客户端的"发送窗口"大小。

简言之,因为TCP是全双工,每一端都有一个发送缓冲区和一个接收缓冲区,其中一端发送窗口的大小决定于对方另一端接收窗口的大小,反之另一端亦然。

为了理解TCP的窗口大小是怎么样变化的,我们先需要理解它的含义。最简单的方式就是认为窗口大小"意味着接收方能接收数据的多少",这也是说接收端在应用程序读取buffer中数据之前,能从对端连接接收多少数据。

比如说server端窗口大小是360,那么就意味着server端一次只能从客户端接收不超过360bytes的数据。当server端收到数据,它会将数据放到buffer里,然后server端必须对数据做两件事:

1. server端必须发送一个 ACK 到client端来确认数据已经收到;

2. server端必须处理这份数据,把它交给上层的应用程序。

要区分上面两件事对理解窗口很重要,接收方收到数据后会发送确认,但是数据并不一定从buffer里马上取走,这受应用层逻辑控制。所以很有可能如果接收数据过快,而取走数据过慢,就会导致buffer满。一旦这种情况发生,就用窗口大小来开始调整,以防接收方负载过高。

正是因为窗口大小的调整可以用来调节数据传输的速率,所以就可以实现TCP的流控,在传输层的流控就是典型的例子,流控对于TCP的通信是很重要的,通过增大或者减小窗口的大小,client和server各自确保彼此设备发数据和收数据平衡。

下面举一个例子,来看TCP窗口大小变化怎样实现流控。client端和server端已经三次握手建立TCP连接,总窗口大小是TCP建立连接时候确定的。黑色框代表client和server总的窗口大小,红色框代表实际可用的窗口大小。初始化的时候默认client和server总窗口和可用端口分别都是360。另外,假设Client总共发送400bytes数据,其中SND.WND、RCV.WND分别表示发送窗口、接收窗口大小,SND.UNA,SND.NXT分别表示确认号、当前待发送数据的指针编号。


1)client 发送140bytes到server端,Seq=1,Length=140;可用窗口大小往前移动,变成220bytes,总窗口大小不变,依然是360。这中间的140是已发送,等待确认,故SND.UNA=1,SND.NXT=141;

2)server端收到140bytes,放入buffer中,但是应用程序很繁忙,只取出40个字节。这时候可用窗口大小: 260(360-140+40)。接着server端要给client发确认,Ack=141,Window=260。黑框左边缘向前移动,表示140字节已经确认收到,但是应用程序太慢,处理很忙导致我现在只能接收260bytes(回顾下上面server端收到数据要做的两件事);

3)client收到来自server端的ack=141回应,首先总窗口左边缘向前移动,SND.UNA=141表示第一步的140bytes server已经收到,剩下400-140=260字节的数据。接着被告知server的可接收窗口是260,client就调整自己的发送窗口是260,表示一次发数据不能超过260;

4)client再发送180bytes,可用窗口变成80(260-180),等待确认发送的180bytes,SND.UNA=141,SND.NXT=321;

5)server收到180bytes,放入buffer中,应用程序依然很繁忙,这次一个字节都不处理。此时可用窗口大小:80(260-180),然后发180的 ack=321给client,并告知窗口大小80;

6)client收到ack=321,确认之前发送的180已经到达,SND.UNA=321,剩余数据还有80字节,SND.NXT=321。被告知server端接收窗口大小是80,调整自己的发送窗口大小为80;

7)client发送80bytes,Seq Num=321,Length=80,可用窗口变成0(80-80),等待确认发送的80bytes,SND.UNA=321,SND.NXT=401,至此400bytes数据发送完毕;

8)server收到80bytes,放入buffer中,应用程序依然很繁忙,一个字节都不处理。此时可用窗口大小:0(80-80),然后发80个bytes的 ack=401给client,并告知窗口大小=0;

9)client收到ack=401,确认之前发送的80个字节已经到达,SND.UNA=401。被告知server端接收窗口大小是0,调整自己的发送窗口大小为0,此时无论client是否还有数据要发送,都不能再发了。

再配一个图说明通过滑动窗口如何控制流量,假设发送端每次最多可以发送1000字节,并且初始窗口协定为2400字节,感兴趣的朋友不妨自己阅读该图之含义。


总结

窗口就是量化接收端和服务端当前能处理数据的能力。如发现接收端的窗口越来越小,或者越来越大,说明两端的数据处理和传输可能会有问题。

1. 接收端的窗口越来越小,那么就是接收端处理不过来(1.发的程序太快,太多;2.收的程序太慢,太少;3.发端带宽比收端带宽更大),会导致接收端发送给发送端的窗口变小,从而发送端调整发送窗口大小,降低发送速度,网络流量就会下降。

2. 接收端的窗口越来越大,那么就是发送端处理不过来(1.收的程序太快,太多;2.发的程序太慢,太少;3.发端带宽比收端带宽更小),会导致接收端发送给发送端的窗口变大,从而发送端调整发送窗口大小,增加发送速度,网络流量就会升高。

来源参考:
http://www.jianshu.com/p/8afbbdd4af48


分类:网络日志| 查看评论
相关文章
文章点击排行
本年度文章点击排行
发表评论:
  • 昵称: *
  • 邮箱: *
  • 网址:
  • 评论:(最多100字)
  • 验证码: