TCP采用个各类办法来减小流量的传输量以及信道的利用率。html
TCP容许延迟一会再发送ACK,这样能够将ACK和相同方向的数据结合起来进行发送,从而下降ACK的数量,在必定程度上减轻网络负载。算法
图中经过延迟ACK减小了一个ACK的传输数量缓存
滑动窗口的工做原理在以前已经作了详细的介绍,在滑动窗口中有一个很重要的概念:窗口大小。问题来了,TCP是如何设置窗口大小的呢?在介绍以前先看一下TCP的缓存结构。网络
对于TCP来讲接收和发送方都维护着一个缓存。看上图会发现个问题:若是写进程写的速度大于读进程的读取速度,这样会致使接收缓存溢出,最终致使发送失败。因此引入了窗口大小的概念,接收方经过ACK来实时告知发送方本身剩余缓存的大小(即本身还能接收多少数据),这个大小就是滑动窗口的大小,在传输的过程当中,每一次ack接收方会根据本身的缓存大小动态的调整窗口的大小,下图详细展现了这一过程。性能
上面滑动窗口的展现中最终发送窗口变成了0.spa
当发送方收到窗口为0的参数后,便再也不发送数据给接收方,这个时候接收方进程一直在读取数据,最终接收方的TCP缓存会清空,有空间接收数据,这个时候接收方会经过一个ack通知发送方窗口的大小,可是这个ack有可能会丢失(ack没有重传功能),发送方由于窗口时0,一直没有发送数据,因此没法得知最新的窗口大小,通讯双方都进入了一直等待状态。设计
为了解决这个问题,TCP为每个连接设计了一个持续计数器(persistence timer),当窗口大小为0时,就会启动这个计数器,当计数器到期后会发送一个零窗口(zero window)探测报文段(一个字节),接收方经过确认这个探测报文时能够告知发送方最新的窗口大小。(TCP规定,就算窗口为0,也要接收零窗口探测报文)。下图展现了这种case。htm
通俗来解释这个场景就是一架能够坐500人的飞机只拉1个乘客和5个机组人员,资源极大的浪费。blog
以太网最大传输单元(MTU:max transmission unit)为1500字节,TCP+IP的头部字段为40字节,因此TCP的最大报文(MSS:Max segment size)长度为1460字节。当传递的报文的大小远远小于1460。尤为小于头部40的时候,就出现了上面说的一个大飞机拉一我的的状况,其中MTU为飞机的容量(500),机组乘员为TCP/IP头部(5),传输报文为乘客(1)。队列
发送窗口的size大于MSS,可是须要发送的数据远远小于MSS,这种状况的解决采用nagle算法:
if there is new data to send #有数据要发送
# 发送窗口缓冲区和队列数据 >=mss,队列数据(available data)为原有的队列数据加上新到来的数据
# 也就是说缓冲区数据超过mss大小,nagle算法尽量发送足够大的数据包
if the window size >= MSS and available data is >= MSS
send complete MSS segment now # 当即发送
else
if there is unconfirmed data still in the pipe # 前一次发送的包没有收到ack
# 将该包数据放入队列中,直到收到一个ack再发送缓冲区数据
enqueue data in the buffer until an acknowledge is received
else
send data immediately # 当即发送
end if
end if
end if
else里面有小块数据(小于MSS)时候,解释下:这个时候须要看是否还有已经发送待确认的数据,若是有则等着先不发,等于先在发送端攒数据。某种程度上又变成了停等协议,若是ACK返回的比较慢,小数据等待的时间就会比较长,最终会影响性能。有些状况并不适用nagle算法,好比人机交互的游戏等,能够禁用nagle算法。
对于接收端来讲,若是接收缓存的窗口大小小于MSS或者某个给定的值后,直接ack 接收窗口的size为0。这样当发送方收到接收窗口为0时,则中止发送数据进行等待,在此期间,接收端的应用一直在读取数据,这样接收窗口会慢慢变大,最终经过发送方的0窗口探测请求告知发送方最新的窗口大小,从而再次开始数据传输。
以上介绍了TCP流量控制的一个总体过程,全文完。