首页 > 代码库 > TCP/IP协议详解 卷一:协议 20章、TCP的成块数据流
TCP/IP协议详解 卷一:协议 20章、TCP的成块数据流
1、引言
该协议允许发送方在停止并等待确认前可以连续发送多个分组,由于发送发不必每发送一个分组就停下来等待确认,因此该协议可以加速数据的传输。
2、正常数据流
数据传输过程中,经受时延的确认。一般来说,发送端发送一个数据报之后,接收端都会发送一个对这个数据报的确认。但是使用TCP的滑动窗口协议的时候,接收方不必对每一个接收的数据报进行确认。我们在上一个章节有提到过,捎带数据的ACK。这里我们要介绍的是,ACK的累积机制。
在TCP中,ACK是累积的,它们表现为接收方已经正确接收了一直到确认序号减1的所有字节。或者说,发送端会一直发送数据直到接收端缓存已满(或者接近),而接收方对这些数据只要以一个ACK的方式进行确认就可以了,类似前面的经受时延的ACK。
发送同一段数据可能有不同的时间序列
- 由于发送方和接收方处理数据的能力不同,那么时间序列也可能不同。(快的发送方和慢的接收方)
- 比如接收方处理得慢,那么发送方必须等到接收方处理完窗口里面的数据才能发送。
- 如果接收方的缓冲区数据满了,会返回一个ACK,并通知窗口为0.
- 过一段时间缓冲区有位置了,会再发一个ACK通知窗口大小。(并不是有位置就马上通知)
3、滑动窗口
TCP中采用滑动窗口来进行传输控制,滑动窗口的大小意味着接收方还有多大的缓冲区可以用于接收数据。发送方可以通过滑动窗口的大小来确定应该发送多少字节的数据。
滑动窗口协议的基本原理就是在任意时刻,发送方都维持了一个连续的允许发送的帧的序号,称为发送窗口;同时,接收方也维持了一个连续的允许接收的帧的序号,称为接收窗口。发送窗口和接收窗口的序号的上下界不一定要一样,甚至大小也可以不同。发送方窗口内的序列号代表了那些已经被发送,但是还没有被确认的帧,或者是可以被发送的帧。
窗口移动:
(1)窗口左边沿向右边沿靠近为窗口合拢。 (发生在数据被发送和确认时)
(2)窗口右边沿向右边移动为窗口张开。 (发生在另一端的接收进程读取已经确认的数据并释放了TCP的接收缓存时)
(3)窗口右边沿向左边移动为窗口收缩。(RFC强烈建议不要使用这种方式)
如果左边沿到达右边沿,则称其为一个0窗口,此时发送方一般不能再发送数据报,但有两种情况除外,一种情况是可以发送紧急数据,例如,允许用户终止在远端机上的运行进程。另一种情况是发送方可以发送一个1字节的数据报来通知接收方重新声明它希望接收的下一字节及发送方的滑动窗口大小。
4、窗口大小
由接收方提供的窗口大小通常可以由接收进程控制,这将影响TCP的性能。
窗口大小由进程控制,插口API允许进程设置发送和接收缓存的大小,接收缓存的大小是该连接上所能够通告的最大窗口大小。默认的4096并不是最理想的窗口大小,而16384则可以使吞吐量大大的增加。
滑动窗口是用来加速数据传输。TCP要保证“可靠”,就需要对一个数据包进行ack确认表示接收端收到(窗口张开)。有了滑动窗口,接收端就可以等收到许多包后只发一个ack包,确认之前已经收到过的多个数据包。有了滑动窗口,发送端在发送完一个数据包后不用等待它的ack,在滑动窗口大小内可以继续发送其他数据包(窗口合拢)。
发送的数据TCP包都有一个序号。它是这么计算的:最初发送SYN时,有一个初始序号,根据RFC的定义,各个操作系统的实现都是与系统时间相关的。之后,序号的值会不断的增加,比如原来的序号是100,如果这个TCP包的数据有10个字节,那么下次的TCP包序号会变成110。
滑动窗口用于加速传输,比如发了一个seq=100的包,理应收到这个包的确认ack=101后再继续发下一个包,但有了滑动窗口,只要新包的seq与没有得到确认的最小seq之差小于滑动窗口大小,就可以继续发。
因为窗口的左边沿受另一端发送的确认序号的控制,因此不可能向左边沿移动。如果接收到一个指示窗口左边沿向左移动的ACK,则它被认为是一个重复的ACK,并被丢弃。
5、PUSH标志
发送方使用该标志通知接收方将所收到的数据全部提交给接收进程。这里的数据包括与PUSH一起传送的数据以及接收方TCP已经为接收进程收到的其它数据。
(1)发送方将发送缓冲区的数据立即发送给接收方。
(2)接收方将接收缓冲区的数据立即提交给接收进程。
如果待发送数据会清空发送缓冲区,该包将自动设置PUSH标志。
6、慢启动
如果在发送方和接收方之间存在多个路由器和速度较慢的链路时(广域网),一开始就不断发送报文段直至达到接收方的窗口满为止,这样的行为可能导致拥塞。
慢启动算法(slow start)通过观察到新分组进入网络的速率应该与另一端返回确认的速率相同而进行工作。
慢启动需要加入一个新的窗口概念——拥塞窗口,cwnd.
拥塞窗口初始化为1个报文段,每接收到一个ACK就增加一个报文段。(cwnd以字节为单位,但是慢启动以报文段大小为单位,也就是1个报文段。)
大小变化:1->2->4->8…… 可以看出拥塞窗口的大小是以指数方式增长的。
发送方取拥塞窗口与通告窗口的最小值作为发送上限。(就是你能发送的大小和对方能接收的大小的最小值)
慢启动算法用于保证新分组进入网络的速率与另一端返回确定的速率相等。
拥塞窗口是发送使用的流量控制,通告窗口是接收方使用的流量控制。
7、成块数据的吞吐量
吞吐量 概念:单位时间内成功传送数据的数量
发送方和接收方之间的路径称为管道。
带宽时延乘积 capacity(bit)=bandwidth(b/s) x round-trip time(s)
通道容量=带宽 x 往返时间 (容量=时间 x 速度)也就是整个通道能装下的容量大小
拥塞:当数据到达一个打的管道(如一个快速局域网)并向一个较小的管道(如一个较慢的广域网)发送时,便会发生拥塞。当多个输入流到达一个路由器,而路由器的输出流小于这些输入流的总和时也会发生拥塞。
当发送方收到ACK的时候,拥塞窗口的值就+1.
TCP的自计时:由于接收方只在数据到达的时候才生成ACK,所以发送方接收到ACK之间的间隔与数据到达接收方的间隔是一致的。(然而在实际中,返回路径上的排队(拥塞)会改变ACK的到达率)
在拥塞窗口的值足够大之后,发送方和接收方之间的管道(pipe)被填满,此时无论拥塞窗口和通告窗口的值为多少,管道都不能再容纳更多的数据。
当接收方在某个时间段从网络上移走一个报文段,发送方就再发送一个报文段到网络上。
它们就像一辆挤满人的公交车,只有有人下车,才能有其他人上车。
但是不管有多少报文段填充了这个管道,返回路径上总是有相同数目的ACK,这就是理想的稳定状态。
8、紧急方式
“紧急方式”使一端可以告诉另一端有些具有某种方式的“紧急数据”已经放置在普通的数据流中,接收方收到通知,并决定如何处理。
可以通过设置TCP首部中的两个字段来发出这种从一端到另一端的紧急数据已经被放置在数据流中的通知。URG比特被置为1,并且一个16bit的紧急指针放置为一个正的偏移量,该偏移量必须与TCP首部中的序号字段相加,以便得出紧急数据的最后一个字节的序号。
当紧急数据进入发送缓冲区后,下一个将要发送的数据(可能是紧急,也可能不是)的URG比特置为1,发送给接收方。接收方知道后就知道发送方处于紧急状态(仅仅知道而已,不会采取什么措施,它会通知应用层现在有紧急数据,你自己看着办),直到接收到最后一个字节的紧急数据后解除这种状态。
如果接收方通告窗口为0,那么数据无法发送出去,但是URG比特这个报文还是会发送出去,通知对面我这边有紧急数据。
人们常常错误的将紧急数据称之为带外数据。TCP紧急方式只是一个从发送发到接收方的通知,该通知告诉接收方紧急数据已经被发送,并提供该数据最后一个字节的序号。应用程序使用的有关紧急数据部分的编程接口常常都不是最佳的,从而导致更多的混乱。
9、小结
没有一种单一的方法可以使用TCP进行成块数据的交换。这是一个依赖许多因素的动态处理过程,有些因素我们可以控制(发送和接收缓存的大小),而另一方面我们则没有办法控制(网络阻塞、与实现有关的特征)。
进行成块数据有效传输的最重要的方法是TCP的滑动窗口协议。
TCP/IP协议详解 卷一:协议 20章、TCP的成块数据流