TCP/IP协议详解卷一:Chapter24 笔记

Chapter 24 TCP的未来和性能

TCP已经在从1200 b/s的拨号SLIP链路到以太数据链路上运行了许多年。在80年代和90年代初期,以太网是运行TCP/IP最主要的数据链路方式。虽然TCP在比以太网速率高的环境(如T2电话线、FDDI及千兆比网络)中也能够正确运行,但在这些高速率环境下, TCP的某些限制就会暴露出来。

本章讨论TCP的一些修改建议,这些建议可以使TCP在高速率环境中获得最大的吞吐量。首先要讨论前面已经碰到过的路径MTU发现机制,本章主要关注它如何与TCP协同工作。这个机制通常可以使TCP为非本地的连接使用大于536字节的MTU,从而增加吞吐量。

接着介绍长肥管道(long fat pipe),也就是那些具有很大的带宽时延乘积的网络,以及TCP在这些网络上所具有的局限性。为处理长肥管道,我们描述两个新的TCP选项:窗口扩大选项(用来增加TCP的最大窗口,使之超过65535字节)和时间戳选项。后面这个选项可以使TCP对报文段进行更加精确的RTT测量,还可以在高速率下对可能发生的序号回绕提供保护。

我们还将介绍建议的T/TCP,这是为增加事务功能而对TCP进行的修改。通信的事务模式以客户的请求将被服务器应答的响应为主要特征。这是客户服务器计算的常见模型。T/TCP的目的就是减少两端交换的报文段数量,避免三次握手和使用4个报文段进行连接的关闭,从而使客户可以在一个RTT和处理请求所必需的时间内收到服务器的应答。

这些新选项(路径MTU发现、窗口扩大选项、时间戳选项和T/TCP)中令人印象最深刻的就是它们与现有的TCP实现能够向后兼容,即包括这些新选项的系统仍然可以与原有的旧系统进行交互。除了在一个ICMP报文中为路径MTU发现增加了一个额外字段之外,这些新的选项只需要在那些需要使用它们的端系统中进行实现。

24.2 路径MTU发现

路径MTU是当前在两个主机之间的路径上任何网络上的最小MTU。路径MTU发现在IP首部中继承并设置“不要分片(DF)”比特,来发现当前路径上的路由器是否需要对正在发送的IP数据报进行分片。如果一个待转发的IP数据报被设置DF比特,而其长度又超过了MTU,那么路由器将返回ICMP不可达的差错。在11.7节我们显示了某版本的traceroute程序使用该机制来决定目的地的路径MTU。在11.8节我们看到UDP是怎样处理路径MTU发现的。在本节我们将讨论这个机制是如何按照RFC 1191中规定的那样在TCP中进行使用的。

TCP的路径MTU发现按如下方式进行:在连接建立时, TCP使用输出接口或对端声明的MSS中的最小MTU作为起始的报文段大小。路径MTU发现不允许TCP超过对端声明的MSS。如果对端没有指定一个MSS,则默认为536。一旦选定了起始的报文段大小,在该连接上的所有被TCP发送的IP数据报都将被设置DF比特。如果某个中间路由器需要对一个设置了DF标志的数据报进行分片,它就丢弃这个数据报,并产生一个ICMP的“不能分片”差错。如果收到这个ICMP差错, TCP就减少段大小并进行重传。如果路由器产生的是一个较新的该类ICMP差错,则报文段大小被设置为下一跳的MTU减去IP和TCP的首部长度。如果是一个较旧的该类ICMP差错,则必须尝试下一个可能的最小MTU。当由这个ICMP差错引起的重传发生时,拥塞窗口不需要变化,但要启动慢启动。

由于路由可以动态变化,因此在最后一次减少路径MTU的一段时间以后,可以尝试使用一个较大的值(直到等于对端声明的MSS或输出接口MTU的最小值)。RFC 1191推荐这个时间间隔为10分钟。

在对非本地目的地,默认的MSS通常为536字节,路径MTU发现可以避免在通过MTU小于576(这非常罕见)的中间链路时进行分片。对于本地目的主机,也可以避免在中间链路(如以太网)的MTU小于端点网络(如令牌环网)的情况下进行分片。但为了能使路径MTU更加有用和充分利用MTU大于576的广域网,一个实现必须停止使用为非本地目的制定的536的MTU默认值。MSS的一个较好的选择是输出接口的MTU(当然要减去IP和TCP的首部大小)。

24.2.1 一个例子

我们在solaris上运行sock程序并向slip上的丢弃服务器进行一个512字节的写操作:

solaris % sock -i -n1 -w512 slip discard

在主机sun的SLIP接口上收集的tcpdump的输出结果如下:
在这里插入图片描述

24.2.2 大分组还是小分组

在[Bellovin 1993]中的测量表明,分组并不一定是越大越好。考虑下面的例子。我们通过4个路由器(R1-R2-R3-R4)发送8192个字节,每个路由器与一个T1电话线(1544000 b/s)相连。

首先我们使用两个4096字节的分组,从R1到R4它需要花费4个单位时间来发送所有的8192字节。每一跳的时间为 ( 4096 B + 40 B ) × 8 b / B 1544000 b / s = 21.4 m s / 跳 \frac{(4096B + 40B) \times 8b/B}{1544000 b/s} = 21.4ms/跳 1544000b/s(4096B+40B)×8b/B=21.4ms/(将TCP和IP的首部算为40字节)。发送数据的整个时间为分组个数加上跳数减1,从图中可以看到是4个单位时间,或85.6ms。每个链路空闲2个单位时间,或42.8ms。

当我们发送16个512字节的分组时,这将花费更多的单位时间,但是由于发送的分组较短,因此每个单位时间较小。 ( 512 B + 40 B ) × 8 b / B 1544000 b / s = 2.9 m s / 跳 \frac{(512B + 40B) \times 8b/B}{1544000 b/s} = 2.9ms/跳 1544000b/s(512B+40B)×8b/B=2.9ms/现在总时间为 18 × 2.9 = 52.2 m s 18 \times 2.9 = 52.2 ms 18×2.9=52.2ms。每个链路也空闲2个单位的时间,即5.8ms。

24.3 长肥管道

在20.7节,我们把一个连接的容量表示为 c a p a c i t y ( b ) = b a n d w i d t h ( b / s ) × r o u n d  ⁣ −  ⁣ t r i p   t i m e ( s ) capacity(b) = bandwidth(b/s) \times round \!-\! trip\: time(s) capacity(b)=bandwidth(b/s)×roundtriptime(s)并称之为带宽时延乘积。也可称它为两端的管道大小。当这个乘积变得越来越大时, TCP的某些局限性就会暴露出来。
具有大的带宽时延乘积的网络被称为长肥网络( Long Fat Network ,即LFN,发音为“elefan(t)s”),而一个运行在LFN上的TCP连接被称为长肥管道。使用长肥管道会遇到多种问题。

  1. TCP首部中窗口大小为16 bit,从而将窗口限制在65535个字节内。但是长肥网络需要一个更大的窗口来提供最大的吞吐量。窗口扩大选项可以解决这个问题。
  2. 在一个长肥网络LFN内的分组丢失会使吞吐量急剧减少。如果只有一个报文段丢失,我们需要利用快速重传和快速恢复算法来使管道避免耗尽。但是即使使用这些算法,在一个窗口内发生的多个分组丢失也会典型地使管道耗尽(如果管道耗尽了,慢启动会使它渐渐填满,但这个过程将需要经过多个RTT)。
  3. 许多TCP实现对每个窗口的RTT仅进行一次测量。它们并不对每个报文段进行RTT测量。在一个长肥网络LFN上需要更好的RTT测量机制。时间戳选项允许更多的报文段被计时,包括重传。
  4. TCP对每个字节数据使用一个32 bit无符号的序号来进行标识。如果在网络中有一个被延迟一段时间的报文段,它所在的连接已被释放,而一个新的连接在这两个主机之间又建立了,怎样才能防止这样的报文段再次出现呢?IP首部中的TTL字段以及TCP中的最大的报文段生存时间(MSL)可以阻止这种情况的发生。
    由于序号空间是有限的,在已经传输了4 294 967 296个字节以后序号会被重用。在长肥网络LFN上,如果一个包含序号N字节数据的报文段在网络上被迟延并在连接仍然有效时又出现,会发生什么情况呢?网络是否足够快以至于在不到一个MSL的时候序号就发生了回绕?在一个以太网上要发送如此多的数据通常需要60分钟左右。但是在带宽增加时,这个时间将会减少:一个T3的电话线(45 Mb/s)在12分钟内会发生回绕, FDDI(100 Mb/s)为5分钟,而一个千兆比网络(1000 Mb/s)则为34秒。这时问题不再是带宽时延乘积,而在于带宽本身。此时就需要使用TCP的时间戳选项的PAWS(Protection Against Wrapped Sequence numbers)算法,即保护回绕的序号。

24.4 窗口扩大选项

窗口扩大选项使TCP的窗口定义从16 bit增加为32 bit。这并不是通过修改TCP首部来实现的, TCP首部仍然使用16 bit ,而是通过定义一个TCP选项实现对16 bit 的扩大操作(scaling operation)来完成的。于是TCP在内部将实际的窗口大小维持为32 bit的值。在图18-20可以看到关于这个选项的例子。一个字节的移位记数器取值为0(没有扩大窗口的操作)和14。最大值14表示窗口大小为1073725440字节( 65535 × 2 14 65535\times2^{14} 65535×214)。

这个选项只能够出现在一个SYN报文段中,因此当连接建立起来后,在每个方向的扩大因子是固定的。为了使用窗口扩大,两端必须在它们的SYN报文段中发送这个选项。主动建立连接的一方在其SYN中发送这个选项,但是被动建立连接的一方只能够在收到带有这个选项的SYN之后才可以发送这个选项。每个方向上的扩大因子可以不同。如果主动连接的一方发送一个非零的扩大因子,但是没有从另一端收到一个窗口扩大选项,它就将发送和接收的移位记数器置为0。这就允许较新的系统能够与较旧的、不理解新选项的系统进行互操作。

假定我们正在使用窗口扩大选项,发送移位记数为S,而接收移位记数则为R。于是我们从另一端收到的每一个16 bit的通告窗口将被左移R位以获得实际的通告窗口大小。每次当我们向对方发送一个窗口通告的时候,我们将实际的32 bit窗口大小右移S比特,然后用它来替换TCP首部中的16 bit的值。TCP根据接收缓存的大小自动选择移位计数。这个大小由系统设置,但是通常向应用进程提供了修改途径。
在这里插入图片描述

24.5 时间戳选项

时间戳选项使发送方在每个报文段中放置一个时间戳值。接收方在确认中返回这个数值,从而允许发送方为每一个收到的ACK计算RTT。图18-20显示了时间戳选项的格式。发送方在第1个字段中放置一个32 bit的值,接收方在应答字段中回显这个数值。包含这个选项的TCP首部长度将从正常的20字节增加为32字节。时间戳是一个单调递增的值。由于接收方只需要回显收到的内容,因此不需要关注时间戳单元是什么。这个选项不需要在两个主机之间进行任何形式的时钟同步。主动发起连接的一方在它的SYN中指定选项。

为了减少任一端所维持的状态数量,对于每个连接只保持一个时间戳的数值。选择何时更新这个数值的算法非常简单:

  1. TCP跟踪下一个ACK中将要发送的时间戳的值(一个名为tsrecent的变量)以及最后发送的ACK中的确认序号(一个名为lastack的变量)。这个序号就是接收方期望的序号。
  2. 当一个包含有字节号lastack的报文段到达时,则该报文段中的时间戳被保存在tsrecent中。
  3. 无论何时发送一个时间戳选项, tsrecent就作为时间戳回显应答字段被发送,而序号字段被保存在lastack中。

这个算法能够处理下面两种情况:

  1. 如果ACK被接收方迟延,则作为回显值的时间戳值应该对应于最早被确认的报文段。
  2. 如果一个收到的报文段虽然在窗口范围内但同时又是失序,这就表明前面的报文段已经丢失。当那个丢失的报文段到达时,它的时间戳(而不是失序的报文段的时间戳)将被回显。

24.6 PAWS:防止回绕的序号

PAWS算法不需要在发送方和接收方之间进行任何形式的时间同步。接收方所需要的就是时间戳的值应该单调递增,并且每个窗口至少增加1。
在这里插入图片描述接收方将时间戳视为序列号的一个32 bit的扩展。假定一个报文段在时间B丢失并被重传。还假定这个丢失的报文段在时间E重新出现。由于在时间E重新出现的报文段的时间戳为2,这比最近有效的时间戳小(5或6),因此PAWS算法将其丢弃。

24.7 T/TCP:为事务用的TCP扩展

一个事务(transaction)就是符合下面这些特征的一个客户请求及其随后的服务器响应。

  1. 应该避免连接建立和连接终止的开销,在可能的时候,发送一个请求分组并接收一个应答分组。
  2. 等待时间应当减少到等于RTT与SPT之和。其中RTT(Round-Trip Time)为往返时间,而SPT(Server Processing Time)则是服务器处理请求的时间。
  3. 服务器应当能够检测出重复的请求,并且当收到一个重复的请求时不重新处理事务(避免重新处理意味着服务器不必再次处理请求,而是返回保存的、与该请求对应的应答)。

TCP提供了过多的事务特征,而UDP提供的则不够。通常应用程序使用UDP来构造(避免TCP连接的开销),而许多需要的特征(如动态超时和重传、拥塞避免等)被放置在应用层,一遍又一遍的重新设计和实现。一个较好的解决方法是提供一个能够提供足够多的事务处理功能的运输层。

TCP为处理事务而需要进行的两个改动是避免三次握手缩短WAIT_TIME状态。T/TCP通过使用加速打开来避免三次握手:

  1. 它为打开的连接指定一个32 bit的连接计数(Connection Count, CC),无论主动打开还是被动打开。一个主机的CC值从一个全局计数器中获得,该计数器每次被使用时加1。
  2. 在两个使用T/TCP的主机之间的每一个报文段都包括一个新的TCP选项CC。这个选项的长度为6个字节,包含发送方在该连接上的32 bit的CC值。
  3. 一个主机维持一个缓存,该缓存保留每个主机上一次的CC值,这些值从来自这个主机的一个可接受的SYN报文段中获得。
  4. 当在一个开始的SYN中收到一个CC选项的时候,接收方比较收到的值与为该发送方缓存的CC值。如果接收到的CC比缓存的大,则该SYN是新的,报文段中的任何数据被传递给接收应用进程(服务器)。这个连接被称为半同步。如果接收的CC比缓存的小,或者接收主机上没有对应这个客户的缓存CC,则执行正常的TCP三次握手过程。
  5. 为响应一个开始的SYN,带有SYN和ACK的报文段在另一个被称为CCECHO的选项中回显所接收到的CC值。
  6. 在一个非SYN报文段中的CC值检测和拒绝来自同一个连接的前一个替身的任何重复的报文段。

这种“加速打开”避免了使用三次握手的要求,除非客户或者服务器已经崩溃并重新启动。这样做的代价是服务器必须记住从每个客户接收的最近的CC值。

基于在两个主机之间测量RTT来动态计算TIME_WAIT的延时,可以缩短TIME_WAIT状态。TIME_WAIT时延被设置为8倍的重传超时值RTO。

一个可作为替换的事务协议是通用报文事务协议Versatile Message Transaction Protocol, VMTP),该协议在RFC 1045中进行了描述。与T/TCP是现有协议的一个小的扩充不同,VMTP是使用IP的一个完整的运输层。VMTP处理差错检测、重传和重复压缩。它还支持多播通信。

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页