TCP-IP详解:滑动窗口(Sliding Window)

参考书籍:TCP-IP Guidehtml


TCP的优点

从传输数据来说,TCP/UDP以及其余协议均可以完成数据的传输,从一端传输到另一端,TCP比较出众的一点就是提供一个可靠的,流控的数据传输,因此实现起来要比其余协议复杂的多,先来看下这两个修饰词的意义:缓存

 1. Reliability ,提供TCP的可靠性,TCP的传输要保证数据可以准确到达目的地,若是不能,须要能检测出来而且从新发送数据。服务器

 2. Data Flow Control,提供TCP的流控特性,管理发送数据的速率,不要超过设备的承载能力ide

为了可以实现以上2点,TCP实现了不少细节的功能来保证数据传输,好比说 滑动窗口适应系统,超时重传机制,累计ACK等,此次先介绍一下滑动窗口的一些知识点。优化


滑动窗口引入

在阅读一些文章的时候看到一个大牛作的视频,很是不错易于理解滑动窗口的机制,能够先看下:http://v.youku.com/v_show/id_XNDg1NDUyMDUy.htmlui

IP层协议属于不可靠的协议,IP层并不关系数据是否发送到了对端,TCP经过确认机制来保证数据传输的可靠性,在比较早的时候使用的是send--wait--send的模式,其实这种模式叫作stop-wait模式,发送数据方在发送数据以后会启动定时器,可是若是数据或者ACK丢失,那么定时器到期以后,收不到ACK就认为发送出现情况,要进行重传。这样就会下降了通讯的效率,以下图所示,这种方式被称为 positive acknowledgment with retransmission (PAR)spa



滑动窗口

能够假设一下,来优化一下PAR效率低的缺点,好比我让发送的每个包都有一个id,接收端必须对每个包进行确认,这样设备A一次多发送几个片断,而没必要等候ACK,同时接收端也要告知它可以收多少,这样发送端发起来也有个限制,固然还须要保证顺序性,不要乱序,对于乱序的情况,咱们能够容许等待必定状况下的乱序,好比说先缓存提早到的数据,而后去等待须要的数据,若是必定时间没来就DROP掉,来保证顺序性!3d

在TCP/IP协议栈中,滑动窗口的引入能够解决此问题,先来看从概念上数据分为哪些类code

1. Sent and Acknowledged:这些数据表示已经发送成功并已经被确认的数据,好比图中的前31个bytes,这些数据其实的位置是在窗口以外了,由于窗口内顺序最低的被确认以后,要移除窗口,其实是窗口进行合拢,同时打开接收新的带发送的数据视频

2. Send But Not Yet Acknowledged:这部分数据称为发送但没有被确认,数据被发送出去,没有收到接收端的ACK,认为并无完成发送,这个属于窗口内的数据。

3. Not Sent,Recipient Ready to Receive:这部分是尽快发送的数据,这部分数据已经被加载到缓存中,也就是窗口中了,等待发送,其实这个窗口是彻底有接收方告知的,接收方告知仍是可以接受这些包,因此发送方须要尽快的发送这些包

4. Not Sent,Recipient Not Ready to Receive: 这些数据属于未发送,同时接收端也不容许发送的,由于这些数据已经超出了发送端所接收的范围


对于接收端也是有一个接收窗口的,相似发送端,接收端的数据有3个分类,由于接收端并不须要等待ACK因此它没有相似的接收并确认了的分类,状况以下

1.  Received and ACK Not Send to Process:这部分数据属于接收了数据可是尚未被上层的应用程序接收,也是被缓存在窗口内

2.  Received  Not ACK: 已经接收并,可是尚未回复ACK,这些包可能输属于Delay ACK的范畴了

3.  Not Received:有空位,尚未被接收的数据。

发送窗口和可用窗口

对于发送方来说,窗口内的包括两部分,就是发送窗口(已经发送了,可是没有收到ACK),可用窗口,接收端容许发送可是没有发送的那部分称为可用窗口。

1. Send Window : 20个bytes 这部分值是有接收方在三次握手的时候进行通告的,同时在接收过程当中也不断的通告能够发送的窗口大小,来进行适应

2. Window Already Sent: 已经发送的数据,可是并无收到ACK。


滑动窗口原理

TCP并非每个报文段都会回复ACK的,可能会对两个报文段发送一个ACK,也可能会对多个报文段发送1个ACK【累计ACK】,好比说发送方有1/2/3 3个报文段,先发送了2,3 两个报文段,可是接收方指望收到1报文段,这个时候2,3报文段就只能放在缓存中等待报文1的空洞被填上,若是报文1,一直不来,报文2/3也将被丢弃,若是报文1来了,那么会发送一个ACK对这3个报文进行一次确认。

举一个例子来讲明一下滑动窗口的原理:

1. 假设32~45 这些数据,是上层Application发送给TCP的,TCP将其分红四个Segment来发往internet

2. seg1 32~34 seg3 35~36 seg3 37~41 seg4 42~45  这四个片断,依次发送出去,此时假设接收端之接收到了seg1 seg2 seg4

3. 此时接收端的行为是回复一个ACK包说明已经接收到了32~36的数据,并将seg4进行缓存(保证顺序,产生一个保存seg3 的hole)

4. 发送端收到ACK以后,就会将32~36的数据包从发送并无确认切到发送已经确认,提出窗口,这个时候窗口向右移动

5. 假设接收端通告的Window Size仍然不变,此时窗口右移,产生一些新的空位,这些是接收端容许发送的范畴

6. 对于丢失的seg3,若是超过必定时间,TCP就会从新传送(重传机制),重传成功会seg3 seg4一块被确认,不成功,seg4也将被丢弃

就是不断重复着上述的过程,随着窗口不断滑动,将真个数据流发送到接收端,实际上接收端的Window Size通告也是会变化的,接收端根据这个值来肯定什么时候及发送多少数据,从对数据流进行流控。原理图以下图所示:



滑动窗口动态调整

主要是根据接收端的接收状况,动态去调整Window Size,而后来控制发送端的数据流量

1. 客户端不断快速发送数据,服务器接收相对较慢,看下实验的结果

a. 包175,发送ACK携带WIN = 384,告知客户端,如今只能接收384个字节

b. 包176,客户端果然只发送了384个字节,Wireshark也比较智能,也宣告TCP Window Full

c. 包177,服务器回复一个ACK,并通告窗口为0,说明接收方已经收到全部数据,并保存到缓冲区,可是这个时候应用程序并无接收这些数据,致使缓冲区没有更多的空间,故通告窗口为0, 这也就是所谓的零窗口,零窗口期间,发送方中止发送数据

d. 客户端察觉到窗口为0,则再也不发送数据给接收方

e. 包178,接收方发送一个窗口通告,告知发送方已经有接收数据的能力了,能够发送数据包了

f.  包179,收到窗口通告以后,就发送缓冲区内的数据了.


总结一点,就是接收端能够根据本身的情况通告窗口大小,从而控制发送端的接收,进行流量控制


参考文章

1.http://www.cricode.com/2679.html

2.http://kb.cnblogs.com/page/209100/