TCP的交互数据流

相关博客:https://blog.csdn.net/knowledgebao/article/details/84626184


第19章   TCP的交互数据流

19.1   引言

19.2   交互式输入

19.3   经受时延的确认

19.4   Nagle算法

19.4.1   关闭Nagle算法

19.4.2   一个例子 

19.5   窗口大小通告

19.6   小结


第19章   TCP的交互数据流

19.1   引言

前一章我们介绍了 T C P连接的建立与释放,现在来介绍使用 T C P进行数据传输的有关问题。

一些有关T C P通信量的研究如[Caceres et al. 1991]发现,如果按照分组数量计算,约有一 半的T C P报文段包含成块数据(如 F T P、电子邮件和 U s e n e t新闻),另一半则包含交互数据 (如Te l n e t和R l o g i n)。如果按字节计算,则成块数据与交互数据的比例约为 9 0 %和1 0 %。这是 因为成块数据的报文段基本上都是满长度( f u l l - s i z e d)的(通常为5 1 2字节的用户数据),而 交互数据则小得多(上述研究表明 Te l n e t和R l o g i n分组中通常约9 0 %左右的用户数据小于1 0个 字节)。

很明显,T C P需要同时处理这两类数据,但使用的处理算法则有所不同。本章将以 R l o g i n 应用为例来观察交互数据的传输过程。将揭示经受时延的确认是如何工作的以及 N a g l e算法怎 样减少了通过广域网络传输的小分组的数目,这些算法也同样适用于 Te l n e t应用。下一章我们 将介绍成块数据的传输问题。

19.2   交互式输入

首先来观察在一个 R l o g i n连接上键入一个交互命令时所产生的数据流。许多 T C P / I P的初 学者很吃惊地发现通常每一个交互按键都会产生一个数据分组,也就是说,每次从客户传到 服务器的是一个字节的按键(而不是每次一行)。而且,R l o g i n需要远程系统(服务器)回显 我们(客户)键入的字符。这样就会产 生4个报文段:(1)来自客户的交互按 键;(2)来自服务器的按键确认;(3) 来自服务器的按键回显;( 4)来自客 户的按键回显确认。图 1 9 - 1表示了这个 数据流。

然而,我们一般可以将报文段 2和 3进行合并—按键确认与按键回显一 起发送。下一节将描述这种合并的技术 (称为经受时延的确认)。

本章我们特意使用 R l o g i n作为例 子,因为它每次总是从客户发送一个字节到服务器。在第 2 6章讲到Te l n e t的时候,将会发现它 有一个选项允许客户发送一行到服务器,通过使用这个选项可以减少网络的负载。

图1 9 - 2显示的是当我们键入5个字符d a t e \ n时的数据流(我们没有显示连接建立的过程, 并且去掉了所有的服务类型输出。 B S D / 3 8 6通过设置一个R l o g i n连接的TO S来获得最小时延)。 第1行客户发送字符d到服务器。第2行是该字符的确认及回显(也就是图 1 9 - 1的中间两部分数 据的合并)。第3行是回显字符的确认。与字符a有关的是第4 ~ 6行,与字符t有关的是第7 ~ 9行, 第1 0 ~ 1 2行与字符e有关。第3 ~ 4、6 ~ 7、9 ~ 1 0和1 2 ~ 1 3行之间半秒左右的时间差是键入两个字 符之间的时延。

注意到1 3 ~ 1 5行稍有不同。从客户发送到服务器的是一个字符(按下 R E T U R N键后产生的 U N I X系统中的换行符),而回显的则是两个字符。这两个字符分别是回车和换行字符 (C R / L F),它们的作用是将光标回移到左边并移动到下一行。

第1 6行是来自服务器的d a t e命令的输出。这3 0个字节由2 8个字符与最后的C R / L F组成。紧 接着从服务器发往客户的7个字符(第1 8行)是在服务器主机上的客户提示符: svr4 % 。第1 9 行确认了这7个字符。

 

注意T C P是怎样进行确认的。第1行以序号0发送数据字节,第2行通过将确认序号设为1, 也就是最后成功收到的字节的序号加 1,来对其进行确认(也就是所谓的下一个期望数据的序 号)。在第2行中服务器还向客户发送了一序号为 1的数据,客户在第3行中通过设置确认序号 为2来对该数据进行确认。

19.3   经受时延的确认

在图1 9 - 2中有一些与本节将要论及的时间有关的细微之处。图 1 9 - 3表示了图1 9 - 2中数据交 换的时间系列(在该时间系列中,去掉了所有的窗口通告,并增加了一个记号来表明正在传 输何种数据)。

把从b s d i发送到s r v 4的7个A C K标记为经受时延的A C K。通常T C P在接收到数据时并不 立即发送A C K;相反,它推迟发送,以便将 A C K与需要沿该方向发送的数据一起发送(有时 称这种现象为数据捎带A C K)。绝大多数实现采用的时延为200 ms,也就是说,T C P将以最大 200 ms的时延等待是否有数据一起发送。

如果观察b s d i接收到数据和发送A C K之间的时间差,就会发现它们似乎是随机的: 1 2 3 . 5、6 5 . 6、1 0 9 . 0、1 3 2 . 2、4 2 . 0、1 4 0 . 3和195.8 ms。相反,观察到发送A C K的实际时间(从0开始) 为:1 3 9 . 9、5 3 9 . 3、9 4 0 . 1、1 3 3 9 . 9、1 7 3 9 . 9、1 9 4 0 . 1和2140.1 ms(在图1 9 - 3中用星号标出)。 这些时间之间的差则是 200 ms的整数倍,这里所发生的情况是因为 T C P使用了一个200 ms的 定时器,该定时器以相对于内核引导的 200 ms固定时间溢出。由于将要确认的数据是随机到 达的(在时刻16.4, 474.3, 831.1等),T C P在内核的200 ms定时器的下一次溢出时得到通知。 这有可能是将来1~200 ms中的任何一刻。

如果观察s v r 4为产生所收到的每个字符的回显所使用的时间,则这些时间分别为 1 6 . 5、 1 6 . 3、1 6 . 5、1 6 . 4和17.3 ms。由于这个时间小于200 ms,因此我们在另一端从来没有观察到一 个经受时延的A C K。在经受时延的定时器溢出前总是有数据需要发送(如果有一个约为 16 ms 等待时间越过了内核的 200 ms时钟滴答的边界,则仍可以看到一个经受时延的 A C K。在本例 中我们一个也没有看到)。

在图1 8 - 7中,当为检测超时而使用500 ms的T C P定时器时,我们会看到同样的情况。这两个200 ms和500 ms的定时器都在相对于内核引导的时间处溢出。不论 T C P何时设置一个定时 器,该定时器都可能在将来1~200 ms和1~500 ms的任一处溢出。

Host Requirements RFC声明T C P需要实现一个经受时延的A C K,但时延必须小于 500 ms。

19.4   Nagle算法

在前一节我们看到, 在一个R l o g i n连接上客户一般每次发送一个字节到服务器,这就产生 了一些4 1字节长的分组:2 0字节的I P首部、2 0字节的T C P首部和1个字节的数据。在局域网上, 这些小分组(被称为微小分组( t i n y g r a m))通常不会引起麻烦,因为局域网一般不会出现拥 塞。但在广域网上,这些小分组则会增加拥塞出现的可能。一种简单和好的方法就是采用 RFC 896 [Nagle 1984]中所建议的N a g l e算法。

该算法要求一个 T C P连接上最多只能有一个未被确认的未完成的小分组,在该分组的确 认到达之前不能发送其他的小分组。相反, T C P收集这些少量的分组,并在确认到来时以一 个分组的方式发出去。该算法的优越之处在于它是自适应的:确认到达得越快,数据也就发 送得越快。而在希望减少微小分组数目的低速广域网上,则会发送更少的分组(我们将在 2 2 . 3节看到“小”的含义是小于报文段的大小)。

在图1 9 - 3中可以看到,在以太网上一个字节被发送、确认和回显的平均往返时间约为 1 6 m s。为了产生比这个速度更快的数据,我们每秒键入的字符必须多于 6 0个。这表明在局域网 环境下两个主机之间发送数据时很少使用这个算法。

但是,当往返时间( RT T)增加时,如通过一个广域网,情况就会发生变化。看一下在 主机s l i p和主机v a n g o g h . c s . b e r k e l e y . e d u之间的R l o g i n连接工作的情况。为了从我们 的网络中出去(参看原书封面内侧),需要使用两个S L I P链路和I n t e r n e t。我们希望获得更长 的往返时间。图1 9 - 4显示了当在客户端快速键入字符(像一个快速打字员一样)时一些数据 流的时间系列(去掉了服务类型信息,但保留了窗口通告)。

比较图1 9 - 4与图1 9 - 3,我们首先注意到从s l i p到v a n g o g h不存在经受时延的A C K。这是 因为在时延定时器溢出之前总是有数据等待发送。

其次,注意到从左到右待发数据的长度是不同的,分别为: 1、1、2、1、2、2、3、1和3 个字节。这是因为客户只有收到前一个数据的确认后才发送已经收集的数据。通过使用 N a g l e 算法,为发送1 6个字节的数据客户只需要使用9个报文段,而不再是1 6个。

报文段1 4和1 5看起来似乎是与N a g l e算法相违背的,但我们需要通过检查序号来观察其中 的真相。因为确认序号是 5 4,因此报文段1 4是报文段1 2中确认的应答。但客户在发送该报文 段之前,接收到了来自服务器的报文段 1 3,报文段1 5中包含了对序号为5 6的报文段1 3的确认。 因此即使我们看到从客户到服务器有两个连续返回的报文段,客户也是遵守了 N a g l e算法的。

在图1 9 - 4中可以看到存在一个经受时延的 A C K,但该A C K是从服务器到客户的(报文段 1 2),因为它不包含任何数据,因此我们可以假定这是经受时延的 A C K。服务器当时一定非常 忙,因此无法在服务器的定时器溢出前及时处理所收到的字符。

最后看一下最后两个报文段中数据的数量以及相应的序号。客户发送 3个字节的数据(1 8 , 1 9和2 0),然后服务器确认这3个字节(最后的报文段中的 ACK 21),但是只返回了一个字节 (标号为5 9)。这是因为当服务器的T C P一旦正确收到这3个字节的数据,就会返回对该数据的确认,但只有当R l o g i n服务器发送回显数据时,它才能够发送这些数据的回显。这表明 T C P可以 在应用读取并处理数据前发送所接收数据的确认。T C P确认仅仅表明T C P已经正确接收了数据。 最后一个报文段的窗口大小为8 1 8 9而非8 1 9 2,表明服务器进程尚未读取这三个收到的数据。

19.4.1   关闭Nagle算法

有时我们也需要关闭N a g l e算法。一个典型的例子是 X窗口系统服务器(见3 0 . 5节):小消 息(鼠标移动)必须无时延地发送,以便为进行某种操作的交互用户提供实时的反馈。

这里将举另外一个更容易说明的例子—在一个交互注册过程中键入终端的一个特殊功 能键。这个功能键通常可以产生多个字符序列,经常从 A S C I I码的转义( e s c a p e )字符开始。如 果T C P每次得到一个字符,它很可能会发送序列中的第一个字符( A S C I I码的E S C),然后缓 存其他字符并等待对该字符的确认。但当服务器接收到该字符后,它并不发送确认,而是继 续等待接收序列中的其他字符。这就会经常触发服务器的经受时延的确认算法,表示剩下的 字符没有在200 ms内发送。对交互用户而言,这将产生明显的时延。

插口API用户可以使用TC P _ N O D E L A Y 选项来关闭Nagle算法。 Host Requirements RFC声明T C P必须实现N a g l e算法,但必须为应用提供一种方法 来关闭该算法在某个连接上执行。

19.4.2   一个例子 

可以在N a g l e算法和产生多个字符的按键之间看到这种交互的情况。在主机 s l i p和主机 v a n g o g h . c s . b e r k e l e y . e d u之间建立一个R l o g i n连接,然后按下F 1功能键,这将产生3个 字节:一个e s c a p e、一个左括号和一个 M。然后再按下F 2功能键,这将产生另外 3个字节。图 1 9 - 5表示的是t c p d u m p的输出结果(我们去掉了其中的服务类型和窗口通告)。

图1 9 - 6表示了这个交互过程的时间系列。在该图的下面部分我们给出了从客户发送到服 务器的6个字节和它们的序号以及将要返回的 8个字节的回显。

当r l o g i n客户读取到输入的第1个字节并向T C P写入时,该字节作为报文段 1被发送。这 是F 1键所产生的3个字节中的第1个。它的回显在报文段 2中被返回,此时剩余的 2个字节才被 发送(报文段3)。这两个字节的回显在报文段4被接收,而报文段5则是对它们的确认。

第1个字节的回显为2个字节(报文段2)的原因是因为在A S C I I码中转义符的回显是2个字 节:插入记号和一个左括号。剩下的两个输入字节:一个左括号和一个 M,分别以自身作为 回显内容。

当按下下一个特殊功能键(报文段 6 ~ 1 0)时,也会发生同样的过程。正如我们希望的那 样,在报文段 5和1 0(s l i p发送回显的确认)之间的时间差是 200 ms的整数倍,因为这两个 A C K被进行时延。

现在我们使用一个修改后关闭了 N a g l e算法的r l o g i n版本重复同样的实验。图 1 9 - 7显示 了t c p d u m p的输出结果(同样去掉了其中的服务类型和窗口通告)。

在已知某些报文段在网络上形成交叉的情况下,以该结果构造时间系列则更具有启发性 和指导意义。这个例子同样也需要随着数据流对序号进行仔细的检查。在图 1 9 - 8中显示这个 结果。用图1 9 - 7中t c p d u m p输出的号码对报文段进行了相应的编号。

我们注意到的第1个变化是当3个字节准备好时它们全部被发送(报文段 1、2和3)。没有 时延发生—N a g l e算法被禁止。

在t c p d u m p输出中的下一个分组(报文段 4)中带有来自服务器的第 5个字节及一个确认 序号为4的A C K。这是不正确的,因为客户并不希望接收到第 5个字节,因此它立即发送一个 确认序号为2而不是6的响应(没有被延迟)。看起来一个报文段丢失了,在图 1 9 - 8中我们用虚 线表示。

如何知道这个丢失的报文段中包含第 2、3和4个字节,且其确认序号为 3呢?这是因为正 如在报文段5中声明的那样,我们希望的下一个字节是第 2个字节(每当T C P接收到一个超出 期望序号的失序数据时,它总是发送一个确认序号为其期望序号的确认)。也正是因为丢失的 分组中包含第2、3和4个字节,表明服务器必定已经接收到报文段 2,因此丢失的报文段中的 确认序号一定为3(服务器期望接收的下一个字节号)。最后,注意到重传的报文段 6中包含有 丢失的报文段中的数据和报文段 4,这被称为重新分组化。我们将在 2 2 . 11节对其进行更多的 介绍。

现在回到禁止N a g l e算法的讨论中来。可以观察到键入的下一个特殊功能键所产生的 3个 字节分别作为单独的报文段(报文段 8、9和1 0)被发送。这一次服务器首先回显了报文段 8中 的字节(报文段11),然后回显了报文段9和1 0中的字节(报文段1 2)。

在这个例子中,我们能够观察到的是在跨广域网运行一个交互应用的环境下,当进行多 字节的按键输入时,默认使用N a g l e算法会引起额外的时延。 在第2 1章我们将进行有关时延和重传方面的讨论。

19.5   窗口大小通告

在图1 9 - 4中,我们可以观察到s l i p通告窗口大小为4 0 9 6字节,而v a n g o g h通告其窗口大 小为8 1 9 2个字节。该图中的大多数报文段都包含这两个值中的一个。

然而,报文段5通告的窗口大小为4 0 9 5个字节,这意味着在T C P的缓冲区中仍然有一个字 节等待应用程序( R l o g i n客户)读取。同样,来自客户的下一个报文段声明其窗口大小为 4 0 9 4个字节,这说明仍有两个字节等待读取。

服务器通常通告窗口大小为 8 1 9 2个字节,这是因为服务器在读取并回显接收到的数据之 前,其T C P没有数据发送。当服务器已经读取了来自客户的输入后,来自服务器的数据将被 发送。

然而,在A C K到来时,客户的T C P总是有数据需要发送。这是因为它在等待 A C K的过程 中缓存接收到的字符。当客户 T C P发送缓存的数据时,R l o g i n客户没有机会读取来自服务器的 数据,因此,客户通告的窗口大小总是小于 4 0 9 6。

19.6   小结

交互数据总是以小于最大报文段长度的分组发送。在 R l o g i n中通常只有一个字节从客户发 送到服务器。Te l n e t允许一次发送一行输入数据,但是目前大多数实现仍然发送一个字节。

对于这些小的报文段,接收方使用经受时延的确认方法来判断确认是否可被推迟发送, 以便与回送数据一起发送。这样通常会减少报文段的数目,尤其是对于需要回显用户输入字 符的R l o g i n会话。

在较慢的广域网环境中,通常使用 N a g l e算法来减少这些小报文段的数目。这个算法限制 发送者任何时候只能有一个发送的小报文段未被确认。但我们给出的一个例子也表明有时需 要禁止N a g l e算法的功能。
 

参考质量:

1,链接:pdf文档,TCP的交互数据流   提取码:iwhc 


有任何问题,请联系:[email protected]

猜你喜欢

转载自blog.csdn.net/knowledgebao/article/details/85888414