以下部分内容是自己的理解,可能会有差错,如有发现,欢迎指正。
窗口:
TCP是一个滑动窗口协议,即一个TCP连接的发送端在某个时刻能发多少数据是由滑动窗口控制的,而滑动窗口的大小实际上是由两个窗口共同决定的,一个是接收端的通告窗口,这个窗口值在TCP协议头部信息中有,会随着数据的ACK包发送给发送端,这个值表示的是在接收端的TCP协议缓存中还有多少剩余空间,发送端必须保证发送的数据不超过这个剩余空间以免造成缓冲区溢出,这个窗口是接收端用来进行流量限制的,在传输过程中,通告窗口大小与接收端的进程取出数据的快慢有关。另一个窗口是发送端的拥塞窗口(Congestion window),由发送端维护这个值,在协议头部信息中没有,滑动窗口的大小就是通告窗口和拥塞窗口的较小值,所以拥塞窗口也看做是发送端用来进行流量控制的窗口。滑动窗口的左边沿向右移动称为窗口合拢,发生在发送的数据被确认时(此时,表明数据已被接收端收到,不会再被需要重传,可以从发送端的发送缓存中清除了),滑动窗口的右边沿向右移动称为窗口张开,发生在接收进程从接收端协议缓存中取出数据时。随着发送端不断收到的被发送数据的ACK包,根据ACK包中的确认序号和通告窗口大小使滑动窗口得以不断的合拢和张开,形成滑动窗口的向前滑动。如果接收进程一直不取数据,则会出现0窗口现象,即滑动窗口左边沿与右边沿重合,此时窗口大小为0,就无法再发送数据。
下面附一个TCP协议头的格式和滑动窗口的示意图(截自TCPIP协议详解):
图1.TCP头部结构
图2.滑动窗口示意图
带宽:
这里带宽是指单位时间内从发送端到接收端所能通过的“最高数据率”,是一种硬件限制。TCP发送端和接收端的数据传输数率不可能超过两点间的带宽限制。
RTT:
即Round Trip Time,表示从发送端到接收端的一去一回需要的时间,tcp在数据传输过程中会对RTT进行采样(即对发送的数据包及其ACK的时间差进行测量,并根据测量值更新RTT值,具体的算法TCPIP详解里面有),TCP根据得到的RTT值更新RTO值,即Retransmission TimeOut,就是重传间隔,发送端对每个发出的数据包进行计时,如果在RTO时间内没有收到所发出的数据包的对应ACK,则任务数据包丢失,将重传数据。一般RTO值都比采样得到的RTT值要大。
带宽时延乘积:
带宽时延乘积=带宽*RTT,实际上等于发送端到接收端单向通道的数据容积的两倍,这里单向通道的数据容积可以这样来理解,单向通道看成是一条单行道马路,带宽就是马路的车道数,路上跑的汽车就是数据(不过这里所有汽车的速率都是一样的,且不会有人想超车,大家齐头并进),那么单向通道的数据容积就是这条单行道上摆满车,一共可以摆多少辆。当路面上已经摆满的时候,就不能再往里面放了。这里顺便再说一下发送时延和传播时延的差别,单位数据量发送时延是由带宽决定的,就是带宽的倒数,以马路来类比,比如有10辆车,如果车道数为1,那么这10辆车只能首尾相接的顺序上路,从第一辆车的车头到最后一辆车的车尾可以看作是发送时延,此时就是10辆车的车长,如果把车道数改成10,那么这10辆车可以并排上路,发送时延就变成了一辆车的车长了,由此可见,带宽越高,则发送时延越短,反之则反。传播时延则是由电的传播速度(可以看做是一个)常量以及发送和接收端线路的物理长度决定的,比如从美国到中国,传播时延就很大,而一个局域网内部,传播时延就很小。因为发送时延是与数据量大小有关系的,RTT其实只是考虑传播时延。
介绍了上面的概念后,现在再来看看TCP发送数据时,其速率和这些有什么关系,下边用一些符号表示前面提到过的值,
设滑动窗口大小为W, 发送端和接收端的带宽为B, RTT为Tr。
前面已经说过了,TCP发送数据时受滑动窗口的限制,当TCP将滑动窗口中的数据都发出后,在收到第一个ACK之前,滑动窗口大小是0,不能再发送数据了,必须等待ACK包使滑动窗口移动。那么在理想情况下,ACK包应该在什么时候到达呢?显然,就是在数据发出后的RTT时间后,ACK包到达。这也就是说,现在在不考虑丢包和拥塞情况下,TCP在一个RTT时间内能发出的最大数据量为W,所以不考虑带宽限制下,TCP能一个时刻能达到的最大速度是 V = W/Tr
由此可以看出,如果假设Tr是一个定值,那么决定TCP速率的唯一因素就是TCP的滑动窗口大小。现在再考虑带宽限制,前面说过当马路上摆满车的时候,就无法再往里放车了,同理,TCP发送端在Tr/2时间内,能往通道上放的数据量为 V*Tr/2,当 V*Tr/2<=B*Tr/2时,单向通道容积不构成瓶颈,速率的限制主要来源于窗口大小限制。而当V*Tr/2>B*Tr/2时,则就受到容积限制,即此时速率限制来源于带宽限制。
把V*Tr/2<=B*Tr/2和V*Tr/2>B*Tr/2两边的Tr/2约掉,再把V = W/Tr代入,则可以得到 :
W <= B*Tr 及 W > B*Tr
B*Tr就是带宽时延乘积,取W为TCP能支持窗口的最大值Wmax,当Wmax <= B*Tr时,此时发送和接收端之间的通道就是所谓的长肥管道,即带宽时延乘积大的通道。在我们平时生活中使用的宽带网络,ADSL等环境下,因为带宽都比较小,从而B*Tr也比较小,再加上网络情况比较复杂,拥塞情况比较常见,所以这些网络环境下,TCP速率的主要限制因素在于带宽,丢包率等。长肥管道一般不太常见,多见于一些单位使用的专线网络,在这些网络中速率的主要限制因素就是窗口大小了,这也是传统TCP在这些网络环境中不能充分利用带宽的原因所在(因为传统TCP的窗口大小是用2字节表示的,所以最大只有65535(不考虑窗口扩大选项)),除了专线网络外,随着网络硬件技术的发展,万兆交换机的出现,局域网中也可能会出现带宽时延乘积较大的情况。
总结,在W<B*Tr时,影响TCP发送数据速率的最直接的因素是滑动窗口的大小,TCP的流量控制策略(比如超时时窗口设置为1,重复ACK时窗口减半)最终都是通过控制窗口大小来控制速率,而慢启动,拥塞避免这些流量控制算法实际上就是控制窗口增长方式的算法,也就是控制的是加速度大小。当W>B*Tr时,则影响速率的因素就是带宽了。
现在出现很多基于UDP的可靠传输技术,因为UDP在IP的上层除了加了端口号之外基本上没做其他什么事,所以提供给应用层控制的空间就很大,这些技术也大致都是通过在应用层添加可靠性保证,并扩大窗口大小和改变流量控制策略来克服传统TCP的缺点。
BTW,开源项目UDT其实是个好东西,也是基于UDP的可靠传输,还没来得及深入研究。但是看了下文档知道它给外部提供了流量控制策略定制化接口,这点很好,留给了使用者相当大的灵活性,有时间要研究研究。