Wednesday, December 2, 2015

TCP Sliding Window - 滑动窗口协议



http://www.firefoxbug.com/index.php/archives/2798/
client和server各自协议栈都有自己的buffer,应用层读写数据的源都是协议栈buffer里。以接收端为例,应用程序调用read()时,会从buffer里移走数据到用户空间,应用程序读的速度越快(read(1024)必然比read(1)要快),那么buffer里的内容消费的越快,buffer也会越空。那么TCP就可以告诉client,我现在很闲,你可以发送更多的数据来。"更多"是多少?这就说窗口,窗口就是量化接收端和服务端当前能处理数据的能力。

TCP窗口是如何工作的

client和server端建立连接后,client会告诉server,自己的"接收窗口"大小(自己能接收多少的数据,受上面所说的buffer影响),server端接收到client的"接收窗口"大小,就会变成server端自己的"发送窗口"大小。同样的,server端告诉client自己的"接收窗口"大小,就会变成客户端的"发送窗口"大小。
为了理解TCP的窗口大小是怎么样变化的,我们先需要理解它的含义。最简单的方式就是认为窗口大小"意味着接收方能接收数据的大小",这也是说接收端设备再应用程序读取buffer中数据之前,能从对端连接处理多少数据。比如说server端窗口大小是360,那么就意味着server端一次只能从客户端接收不超过360bytes的数据。当server端收到数据,它会将数据放到buffer里,然后server端必须对这份数据做两件事
1. server端必须发送一个 ACK 到client端来确认数据已经收到
2. server端必须处理这份数据,把它交给对应的应用程序
要区分上面两件事对理解窗口很重要,接收方收到数据后会确认,但是数据并不一定是里面就是从buffer里取出的,这是受应用层逻辑控制的。所以很有可能如果接收数据过快,而取出数据更慢,就会导致buffer满。一旦这种情况发生,窗口大小就开始调整来防止接收方负载过高。
正是因为窗口大小的调整可以用来调节数据传输的速率,所以就可以实现TCP的流控,在传输层的流控就是典型的例子,流控对于TCP的通信是很重要的,通过增大或者减小窗口的大小,client和server各自确保彼此设备发数据和收数据平衡。

通过TCP窗口实现流控

下面举一个例子,来看TCP窗口大小变化怎样实现流控。client端和server端已经三次握手建立TCP连接,总窗口大小是TCP建立连接时候确定的。黑色框代表client和server总的窗口大小,红色框代表实际可用的窗口大小。初始化的时候默认client和server总窗口和可用端口分别都是360。另外,假设Client总共只发送360bytes数据,所以总窗口大小不会往前移动。
TCP窗口变化实现流控
  1. client 发送140bytes到server端,Seq=1,Length=140;可用窗口大小往前移动,变成260bytes,总窗口大小不变,依然是360。这中间的120是已发送,等待确认;
  2. server端收到140bytes,放入buffer中,但是应用程序很繁忙,只取出100个字节。这时候可用窗口大小: 260(360-100)。接着server端要给client发确认,Ack=141,Window=260。黑框左边缘向前移动,表示140字节已经确认收到,但是应用程序太慢,处理很忙导致我现在只能处理260bytes(回顾下上面server端收到数据要做的两件事);
  3. client收到来自server端的ack回应,首先总窗口左边缘向前移动,表示第一步的140bytes server已经收到,剩下260数据。接着被告知server的可接收窗口是260,client就调整自己的发送窗口是260,表示一次发数据不能超过260;
  4. client发送180bytes,可用窗口变成80(260-180),等待确认发送的180bytes;
  5. server收到180bytes,放入buffer中,应用程序依然很繁忙,这次一个字节都不处理。此时可用窗口大小:80(260-180),然后发180 ack给client,并告知窗口大小80;
  6. client收到ack,确认之前发送的180已经到达,剩余数据还有80字节。被告知server端接收窗口大小是80,调整自己的发送窗口大小为80
  7. client发送80bytes,可用窗口变成0(80-80),等待确认发送的80bytes;
  8. server收到180bytes,放入buffer中,应用程序依然很繁忙,一个字节都不处理。此时可用窗口大小:80(80-80),然后发80 ack给client,并告知窗口大小0;
  9. client收到ack,确认之前发送的80已经到达。被告知server端接收窗口大小是0,调整自己的发送窗口大小为0,此时无论client是否还有数据要发送,都不能再发了。

http://www.cnblogs.com/ulihj/archive/2011/01/06/1927613.html
发送和接受方都会维护一个数据帧的序列,这个序列被称作窗口。发送方的窗口大小由接受方确定,目的在于控制发送速度,以免接受方的缓存不够大,而导致溢出,同时控制流量也可以避免网络拥塞。下面图中的4,5,6号数据帧已经被发送出去,但是未收到关联的ACK,7,8,9帧则是等待发送。可以看出发送端的窗口大小为6,这是由接受端告知的(事实上必须考虑拥塞窗口cwnd,这里暂且考虑cwnd>rwnd)。此时如果发送端收到4号ACK,则窗口的左边缘向右收缩,窗口的右边缘则向右扩展,此时窗口就向前“滑动了”,即数据帧10也可以被发送。
点击看大图
    下面就滑动窗口协议做出更详细的说明,这里为了简单起见设定发送方窗口大小为2,接受方大小为1。看下面图:
pic301
后退n协议?
    停等协议虽然实现简单,也能较好的适用恶劣的网络环境,但是显然效率太低。所以有了后退n协议,这也是滑动窗口协议真正的用处,这里发送的窗口大小为n,接受方的窗口仍然为1。具体看下面的图,这里假设n=9:
    首先发送方一口气发送10个数据帧,前面两个帧正确返回了,数据帧2出现了错误,这时发送方被迫重新发送2-8这7个帧,接受方也必须丢弃之前接受的3-8这几个帧。
    后退n协议的好处无疑是提高了效率,但是一旦网络情况糟糕,则会导致大量数据重发,反而不如上面的停等协议,实际上这是很常见的,具体可以参考TCP拥塞控制。
pic302 
选择重传协议?
    后退n协议的另外一个问题是,当有错误帧出现后,总是要重发该帧之后的所有帧,毫无疑问在网络不是很好的情况下会进一步恶化网络状况,重传协议便是用来解决这个问题。原理也很简单,接收端总会缓存所有收到的帧,当某个帧出现错误时,只会要求重传这一个帧,只有当某个序号后的所有帧都正确收到后,才会一起提交给高层应用。重传协议的缺点在于接受端需要更多的缓存。



Labels

Review (572) System Design (334) System Design - Review (198) Java (189) Coding (75) Interview-System Design (65) Interview (63) Book Notes (59) Coding - Review (59) to-do (45) Linux (43) Knowledge (39) Interview-Java (35) Knowledge - Review (32) Database (31) Design Patterns (31) Big Data (29) Product Architecture (28) MultiThread (27) Soft Skills (27) Concurrency (26) Cracking Code Interview (26) Miscs (25) Distributed (24) OOD Design (24) Google (23) Career (22) Interview - Review (21) Java - Code (21) Operating System (21) Interview Q&A (20) System Design - Practice (20) Tips (19) Algorithm (17) Company - Facebook (17) Security (17) How to Ace Interview (16) Brain Teaser (14) Linux - Shell (14) Redis (14) Testing (14) Tools (14) Code Quality (13) Search (13) Spark (13) Spring (13) Company - LinkedIn (12) How to (12) Interview-Database (12) Interview-Operating System (12) Solr (12) Architecture Principles (11) Resource (10) Amazon (9) Cache (9) Git (9) Interview - MultiThread (9) Scalability (9) Trouble Shooting (9) Web Dev (9) Architecture Model (8) Better Programmer (8) Cassandra (8) Company - Uber (8) Java67 (8) Math (8) OO Design principles (8) SOLID (8) Design (7) Interview Corner (7) JVM (7) Java Basics (7) Kafka (7) Mac (7) Machine Learning (7) NoSQL (7) C++ (6) Chrome (6) File System (6) Highscalability (6) How to Better (6) Network (6) Restful (6) CareerCup (5) Code Review (5) Hash (5) How to Interview (5) JDK Source Code (5) JavaScript (5) Leetcode (5) Must Known (5) Python (5)

Popular Posts