首页 理论教育TCP传输控制技术-计算机网络技术

TCP传输控制技术-计算机网络技术

【摘要】:TCP 是可靠的传输层协议,当应用进程将数据交给TCP 后,TCP 就能无差错地交给目的端的应用进程。TCP 使用差错控制机制保证数据的可靠传输,主要的差错控制机制即确认和重传。每个TCP 连接传输数据的第一个字节序号是建立TCP 连接时初始序号加“1”。以字节为单位的滑动窗口TCP 通过滑动窗口机制实现传输的控制。

TCP 是可靠的传输层协议,当应用进程将数据交给TCP 后,TCP 就能无差错地交给目的端的应用进程。TCP 使用差错控制机制保证数据的可靠传输,主要的差错控制机制即确认和重传。

(1)字节编号和确认

如前所述,TCP 提供面向连接的字节流传输服务,也就是说,TCP 协议将要传送的数据看作一个个字节组成的字节流,接收方返回给发送方的确认是按字节进行的,而不是按报文段进行。因此,发送方使用TCP 进行数据传输时,要对数据段进行字节编号,接收端通过对收到数据的字节编号进行确认,实现TCP 的可靠传输。

每个TCP 连接传输数据的第一个字节序号是建立TCP 连接时初始序号加“1”。例如,某条TCP 连接要传送2 000 字节的文件,分成四个TCP 报文段进行传送,每个报文段携带500 个字节,TCP 对第一个字节的编号从10 001 开始(1 000 为TCP 连接建立时随机选择的初始序号),那么每个TCP 报文段的字节编号如下:报文段1 的字节序号为10 001(范围是从1 0001 ~10 500);报文段2 的字节序号为10 501(范围是从10 501 ~11 000);报文段3 的字节序号为11 001(范围是从11 001 ~11 500);报文段4 的字节序号为11 501(范围是从11 501 ~12 000)。

TCP 报文的每个确认序号字段指出接收方希望收到的下一个字节的编号。接收方确认已经收到的最长连续的字节,作为TCP 报文的确认序号的基础,实质即已经接收到报文段的所有字节的确认。这种字节确认的优点是,即使确认丢失,也不一定会导致发送方重传。例如,假设接收方TCP 发送的ACK 报文段的确认序号是1 801,则表明1 800 前所有的字节都已经被接收端收到。如果接收端前面已经发送过确认序号为1 601 的ACK 报文段,但这个报文段丢失了,由于目前已经有确认号为1 801 的报文段,则不需要发送方TCP 重传字节序号1 800以前的报文段,实现了“累计确认”机制。

(2)超时重传和重传定时器

发送方TCP 为了恢复丢失或损坏的报文段,必须对丢失或损坏的报文段进行重传。为了能够判断报文的丢失,当发送方发送报文段后,就启动一个重传定时器,如果在规定的时间内没有收到接收方TCP 返回的确认报文,则重传计时器超时,发送方重传该TCP 报文段。

影响超时重传的关键因素是重传定时器的时间宽度,但确定合适的时间宽度是一件相当困难的事情,因为在互联网环境下,不同主机上的应用进程之间通信可能在一个局域网上进行,也可能穿越多个不同的网络,端到端传输延迟的变化幅度相当大,很难把握从发送数据到接收确认的往返时间。

一般情况下,时间宽度确定的方法为:每当TCP 发送一个报文段,就将发送时刻记录下来;当该报文段的ACK 回来时,再将返回时刻记录下来。这两个时刻的差,记为SampleRTT(当前样本)。接着,TCP 在前一次的RTT 估算值(EstimatedRTT)和SampleRTT 之间通过加权求和计算新的RTT 估算值(EstimatedRTT),这样动态地维持往返时延平均值,具体公式如下:

EstimatedRTT=α×EstimatedRTT+(1 -α)×SampleRTT

其中,0≤α≤1,α 因子决定了EstimatedRTT 对延迟变化的反应速度。当α 接近“1”时,当前样本对RTT 估算值几乎不起作用;而当α 接近“0”时,RTT 估算值紧随延迟的变化而变化。作为折中,TCP 协议规范推荐α 取值为0.8 ~0.9。

TCP 重传定时器的值为EstimatedRTT 的函数,公式如下:

TimeOut=β×EstimatedRTT

当β 接近“1”时,TCP 能迅速检测到报文丢失并重传,从而减少等待时间,但能造成许多不必要的重传。当β 太大时,重传报文的数目减少,但等待确认的时间增加。作为折中,TCP协议规范推荐β 取“2”。

(3)以字节为单位的滑动窗口

TCP 通过滑动窗口机制实现传输的控制。为了说明滑动窗口的工作原理,假设数据只在一个方向上进行,即A 发送数据,B 接收数据并给出确认;其次,将传送的字节取得较小,这样能够简化问题,同时不影响对问题实质的理解。

假设A 接收到B 发来的确认报文段,其中窗口字段的值为“10”,确认号ACK 的值为“31”。A 根据这两个数据构建自己的发送窗口情况,如图8.5所示。此时,A 的发送状态可用三个指针(P1、P2、P3)来描述:P1 指向发送窗口内,接收端期望收到的字节序号,即可发送的首字节序号;P2 指向发送窗口内,允许发送而尚未发送的字节序号;P3 指向发送窗口外,不允许发送的字节序号。此时,由于A 尚未发送数据,因此P1 和P2 是重合的。

图8.5 根据B 的接收窗口构造的发送窗口

在图8.5 中,发送窗口W 用来对发送端进行流量控制。W 的大小表示A 在没有收到B确认的情况下,最多还可连续发送的字节数。在接收端未来得及进行接收处理的情况下,W越大,允许发送端在未收到确认之前可连续发送的数据也越多,从而获得更高的传输效率。考虑到超时重传的需要,凡是已经发送但未确认的数据,必须暂时保留,以备后用。

假设A 已经发送了序号为31 ~35 的数据,A 现在的发送窗口状态如图8.6所示。发送窗口W 内左边的5 个字节(31 ~35)表示已经发送但未收到确认,而右边的5 个字节(36 ~40)是允许发送而尚未发送的数据。

(www.chuimin.cn)

图8.6 发送5 个字节后的发送窗口状态

假设B 接收窗口WR 为“10”。B 现在的接收窗口状态如图8.7所示。在接收窗口左边的数据是已经得到确认并交付主机,所以B 不必再保存这些数据,接收窗口内的序号31 ~40 是允许接收的数据。此时,B 的接收状态可以用两个指针(Q1 和Q2)来描述:Q1 指向接收窗口内,允许接收,但未发送确认的字节序号;Q2 指向接收窗口外,不允许接收的字节序号。

图8.7 B 的接收窗口状态

现在假设B 收到的数据未按序到达,只收到序号为32 ~33,而没有收到序号31,此时B 仍然只能对最高序号给出确认,即确认报文段中的确认号为“31”,而不是“34”,因此Q1 和Q2都不能移动。

若B 收到了序号为“31”的数据,则将“31”及原来收到的“32 ~33”一起交付给主机,并删除这些数据;接着,B 就可以将接收WR 右移三个序号,同时给A 发送确认。A 收到B 的确认后,将发送窗口右移三个序号,但指针P2 不动。

A 继续发送完序号36 ~40 的数据,指针P2 右移到与P3 重合。此时,发送窗口内允许发送的序号已用完,虽然还没有收到确认,但必须停止发送。当A 所设置的超时计时器超时时,A 就进行重传并重置超时计时器,直到收到B 的确认为止。如果A 收到的确认号落在发送窗口之内,A 就将发送窗口右移,并继续发送新的数据。

需要注意的是,虽然A 的发送窗口W 是依据B 的接收窗口WR 来设置的,但两者的大小不一样,这是由于窗口值通过网络传送需要一定的时延。A 还可根据网络当时的拥塞情况减小自己的窗口值,从而达到拥塞控制的目的。对于不按序到达的数据,TCP 没有明确的处理规定,通常将不按序到达的数据暂存在接收窗口中,等待缺失序号的到达,再一并按序交付给主机;为了减少传输开销,TCP 要求接收端具有累积确认的功能。

(4)TCP 的流量控制

流量控制的主要作用是让发送端发送数据的速率不要过快,保证接收端来得及接收。由于发送端和接收端在进行TCP 传输时都要维持一个滑动窗口,这种数据传输过程本身就能够保证TCP 的流量控制。下面以一个例子来说明如何利用滑动窗口实现在TCP 连接上进行流量控制。

通信双方的发送和接收过程如图8.8所示。假设A 向B 发送数据,每一个报文段为1 024字节。在建立连接时,接收端B 设有4 KB 的缓冲区。

首先,A 发送两个报文段,序号分别为SYN=0 和SYN=1 024。B 正确收到后给出确认报文段,确认号为ack=2 048,窗口WR =2 048,表示B 的缓冲空间为2 KB。

A 又发送两个报文段,序号分别为SYN =2 048 和SYN =3 072。B 正确收到后给出确认报文段,确认号为ack=4 096,窗口WR =0,表示自己的缓冲区已满。此时,A 必须停下来,等待接收端主机上的应用程序取走一些数据。

若接收端主机从接收缓冲区读取2 KB 的数据后,B 则发送一个确认报文段给A,这个确认报文段的确认号仍然为ack=4 096,但窗口WR =2 048,表示自己的缓冲空间又有2 KB。

这样,A 由被阻塞的状态转换为可发送数据的状态,继续发送数据。这样,便实现了TCP数据传输的流量控制。

图8.8 TCP 的流量控制

当窗口为“0”时,除了以下两种意外情况外,发送端不能再发送报文段了:

①紧急数据仍可以发送。可要求用户终止远程主机上运行的某个进程,使紧急数据得以发送。

②当B 向A 发送了窗口为“0”的确认报文段后,因应用程序读取了数据,B 的接收缓冲区又有了存储空间,于是B 向A 发送窗口不为“0”的确认报文段。但如果这个报文段在传送过程中丢失,则A 将一直处于等待状态,造成死锁的现象。为了解决这个问题,TCP 为每个连接设置一个持续计时器,当一方收到对方的零窗口确认报文段,就启动持续计时器,若持续计时器超时,就发送一个零窗口探询报文段,以便让接收端重新发送下一个期望的字节号和窗口大小。对方在确认这个探询报文段时应给出现有的允许窗口值。如果窗口值仍然为“0”,则重置持续计时器,否则,死锁僵局结束。