速读原著-TCP/IP(TCP紧急方式)

第20章 TCP的成块数据流

20.8 紧急方式

T C P提供了“紧急方式 ( u rgent mode)”,它使一端可以告诉另一端有些具有某种方式的“紧急数据”已经放置在普通的数据流中。另一端被通知这个紧急数据已被放置在普通数据流中,由接收方决定如何处理。

可以通过设置 T C P首部(图1 7 - 2)中的两个字段来发出这种从一端到另一端的紧急数据已经被放置在数据流中的通知。 U R G比特被置1,并且一个 1 6 b i t的紧急指针被置为一个正的偏移量,该偏移量必须与 T C P首部中的序号字段相加,以便得出紧急数据的最后一个字节的序号。

仍有许多关于紧急指针是指向紧急数据的最后一个字节还是指向紧急数据最后一个字节的下一个字节的争论。最初的 T C P规范给出了两种解释,但Host RequirementsRFC确定指向最后一个字节是正确的。

然而,问题在于大多数的实现(包括源自伯克利的实现)继续使用错误的解释。所有符合Host Requirements RFC的实现都是可兼容的,但很有可能无法与其他大多数主机正确通信。

T C P必须通知接收进程,何时已接收到一个紧急数据指针以及何时某个紧急数据指针还不在此连接上,或者紧急指针是否在数据流中向前移动。接着接收进程可以读取数据流,并必须能够被告知何时碰到了紧急数据指针。只要从接收方当前读取位置到紧急数据指针之间有数据存在,就认为应用程序处于“紧急方式”。在紧急指针通过之后,应用程序便转回到正常方式。

T C P本身对紧急数据知之甚少。没有办法指明紧急数据从数据流的何处开始。 T C P通过连接传送的唯一信息就是紧急方式已经开始( T C P首部中的U R G比特)和指向紧急数据最后一个字节的指针。其他的事情留给应用程序去处理。不幸的是,许多实现不正确地称 T C P的紧急方式为带外数据 (out-of-band data)。如果一个应用程序确实需要一个独立的带外信道,第二个 T C P连接是达到这个目的的最简单的方法(许多运输层确实提供许多人认为的那种真正的带外数据:使用同一个连接的独立的逻辑数据
通道作为正常的数据通道。这是 T C P所没有提供的)。

T C P的紧急方式与带外数据之间的混淆,也是因为主要的编程接口(插口A P I)将TCP的紧急方式映射为称为带外数据的插口。

紧急方式有什么作用呢?两个最常见的例子是 Te l n e t和R l o g i n。当交互用户键入中断键时,我们在第2 6章将看到使用紧急方式来完成这个功能的例子。另一个例子是 F T P,当交互用户放弃一个文件的传输时,我们将在第 2 7章看到这样的一个例子。

Te l n e t和R l o g i n从服务器到客户使用紧急方式是因为在这个方向上的数据流很可能要被客户的T C P停止(也即,它通告了一个大小为 0的窗口)。但是如果服务器进程进入了紧急方式,尽管它不能够发送任何数据,服务器 T C P也会立即发送紧急指针和U R G标志。当客户T C P接收到这个通知时就会通知客户进程,于是客户可以从服务器读取其输入、打开窗口并使数据流动。

如果在接收方处理第一个紧急指针之前,发送方多次进入紧急方式会发生什么情况呢?在数据流中的紧急指针会向前移动,而其在接收方的前一个位置将丢失。接收方只有一个紧急指针,每当对方有新的值到达时它将被覆盖。这意味着如果发送方进入紧急方式时所写的内容对接收方非常重要,那么这些字节数据必须被发送方用某种方式特别标记。我们将看到Te l n e t通过在数据流中加入一个值为 2 5 5的字节作为前缀来标记它所有的命令。

一个例子
让我们观察一下即使是在接收方窗口关闭的情况下, T C P是如何发送紧急数据的。在主机b s d i上启动s o c k程序,并使之在连接建立后和从网络读取前暂停 1 0秒种(通过使用 - P选项),这将使另一端填满发送窗口:

bsdi % sock -i -s -P10 5555

接着我们在主机 s u n上启动客户,使之使用一个 8 1 9 2字节的发送缓存(使用 - S选项)并进行6个向网络写 1 0 2 4字节数据的操作(使用 - n选项)。还指明 - U 5选项,告知它向网络写第5个缓存之前要写 1个字节的数据,并进入紧急数据方式。我们指明详细标志来观察写的顺序:
在这里插入图片描述
我们设置发送缓存为 8 1 9 2个字节,以便让发送应用程序能够立即写所有的数据。图 2 0 - 1 4显示了t c p d u m p输出的这个交换过程的结果(删去了连接建立的过程)。第1 ~ 5行表示发送方用4个1 0 2 4字节的报文段去填充接收方的窗口。然后由于接收方的窗口被填满(第 4行的A C K确认了数据,但并没有移动窗口的右边沿),所以发送方停止发送。

在写了第4个正常数据之后,应用进程写了1个字节并进入紧急方式。第6行是该应用进程写的结果,紧急指针被设置为4 0 9 8。尽管发送方不能发送任何数据,但紧急指针和U R G标志一起被发送。5个这样的A C K在13 ms内被发送(第6 ~ 1 0行)。第1个A C K在应用进程写 1个字节并进入紧急方式时被发送,后面两个在应用进程写最后两个 1 0 2 4字节的数据时被发送(尽管 T C P不能发送这2 0 4 8个字节的数据,可每次当应用程序执行写操作的时候, T C P的输出功能被调用。

当T C P看到正处于紧急方式时,它会发送其他的紧急通知)。第4个A C K在应用进程关闭其T C P连接时被发送( T C P的输出功能再次被调用)。发送应用程序在启动几毫秒后终止—在接收方应用进程已经发出其第一个写操作之前。 T C P将所有的数据进行排队,并在可能时发送出去(这就是为何指明发送缓存为 8 1 9 2字节的原因,因此只有这样才能够把所有的数据都放置在缓存中)。第5个A C K很可能是在接收第 4行的A C K时产生的。发送 T C P很可能在这个A C K到达前便已将其第 4个报文段放入队列以便输出(第 5行)。另一端接收到这个 A C K也会引起T C P输出例程被调用。
在这里插入图片描述
接着,接收方确认最后的 1 0 2 4字节的数据(第 11行),但同时通告窗口为 0。发送方用一个包含紧急通知的报文段进行了响应。

在第1 3行,当应用进程被唤醒、并从接收缓存读取一些数据时,接收方通告窗口为 2 0 4 8字节。于是后面又发送了两个 1 0 2 4字节的报文段(第 1 4和1 5行)。其中,由于紧急指针在第 1个报文段的范围内,因此这个报文段被设置了紧急通知标志,而第 2个报文段则关闭了该标志。

当接收方再次打开窗口(第 1 6行)时,发送方传输最后的数据(序号为 6 1 4 5)并发起正常的连接关闭。

图2 0 - 1 5显示了发送的6 1 4 5个字节数据的序号。可以看到当进入紧急方式时所发送的字节的序号是4 0 9 7,但在图2 0 - 1 4中紧急指针指向4 0 9 8,这证明了该实现(SunOS 4.1.3)将紧急指针设置为紧急数据最后字节的下一个字节。
在这里插入图片描述
该图还可以让我们观察 T C P是如何对应用进程写的数据进行重新分组化的。当进入紧急方式时待输出的 1个字节是与在缓存中的后面 1 0 2 3个字节一同发送的。下一个报文段也包含1 0 2 4字节的数据,而最后一个报文段则只包含一个字节。

发布了1537 篇原创文章 · 获赞 1475 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/weixin_42528266/article/details/104792179
今日推荐