5

在带有 URG 标志的 TCP 段中,也可能有正常数据。接收主机如何处理紧急数据包?如果它不是数据流的一部分,它如何确认紧急数据?它承认其余部分吗?

我知道它通常不使用,但是如果两个主机都支持关于 URG 标志的相同 RFC,它们如何处理带外数据?

如果紧急数据是中止消息,接收方将丢弃所有其他数据,但发送方仍需要确认消息已收到。

4

1 回答 1

12

一点背景:

TCP 紧急机制允许将数据流中的一个点指定为紧急信息的结尾。因此,我们有一个紧急指针,它包含与此 tcp 段中的序列号的正偏移量。该字段仅在设置了 URG 控制位时才有意义。


关于紧急指针的差异:

RFC 793(1981,第 17 页):

紧急指针指向紧随紧急数据的八位字节的序列号。

RFC 1011(1987,第 8 页):

第 17 页是错误的。紧急指针指向紧急数据的最后一个八位字节(而不是非紧急数据的第一个八位字节)。

RFC 1122(1989,第 84 页)中的相同内容:

..紧急指针指向紧急数据序列中最后一个八位字节(不是 LAST+1)的序列号。

可理解的RFC 6093(2011,第 6-7 页)说:

考虑到只要 TCP 发送方和 TCP 接收方都为紧急指针实现相同的语义,那么让紧急指针指向“紧急数据之后的八位字节的序列号”与“最后一个紧急数据的八位字节”,并且所有已知的实现都将紧急指针的语义解释为指向“紧急数据之后的八位字节的序列号”。

因此更新 RFC 793、RFC 1011 和 RFC 1122 是

紧急指针指向紧随紧急数据的八位字节的序列号。

它几乎满足所有现有的 TCP 实现。

注意:Linux 提供了net.ipv4.tcp_stdurg sysctl覆盖默认行为的方法,但这sysctl只会影响传入段的处理。传出段中的紧急指针仍将按照 RFC 793 中的规定进行设置。


关于数据处理

您可以通过两种方式获取紧急数据(请记住,“紧急数据”的 TCP 概念作为“带外数据”映射到套接字 API):

  • recvMSG_OOB标志集一起使用。(通常你应该用类似的东西建立套接字的所有权fcntl(sock, F_SETOWN, getpid());并为 建立一个信号处理程序SIGURG)。因此,您将收到SIGURG信号通知。数据将与普通数据流分开读取。

  • 使用recvMSG_OOB设置标志。以前,您应该SO_OOBINLINE这样设置套接字选项:

    int so_oobinline = 1; /* true */
    setsockopt(sock, SOL_SOCKET, SO_OOBINLINE, &so_oobinline, sizeof so_oobinline);

    数据保持“在线”。您可以借助以下方法确定紧急指针ioctl

    int flag; /* True when at mark */
    ioctl(sock, SIOCATMARK, &flag);

此外,如上所述,建议新应用程序根本不要使用紧急数据机制来使用(如果是)在线接收。
来自 RFC 1122:

TCP 紧急机制不是发送“带外”数据的机制:所谓的“紧急数据”应该“在线”传递给 TCP 用户。

同样来自 RFC 793:

TCP 不会尝试定义用户在收到待处理紧急数据通知后具体做什么

所以你可以随心所欲地处理。这是一个应用程序级别的问题。

因此,关于删除所有其他数据时的确认问题的答案是“您可以在您的应用程序中实现它”。
至于tcp-ack,在紧急数据的情况下,我没有发现它有什么特别之处。



关于“紧急数据”的长度

几乎所有的实现都只能提供一个字节的“带外数据”。
RFC 6093 说:

如果在应用程序读取未决“带外”字节之前接收到“紧急数据”的连续指示,则该未决字节将被丢弃(即,被“紧急数据”的新字节覆盖)。

所以 TCP 紧急模式及其紧急指针在实践中不能提供紧急数据的边界标记。
有传言说有一些实现将每个接收到的紧急字节排队。众所周知,他们中的一些人未能对他们排队的“紧急数据”数量实施任何限制。因此,它们容易受到微不足道的资源耗尽攻击。


PS 以上所有内容可能比所要求的要多一点,但这只是为了让不熟悉这个问题的人清楚。


一些更有用的链接:
TCP 紧急指针、缓冲区管理和“发送”调用
TCP 中推送和紧急标志之间的区别
理解紧急指针

于 2016-12-01T13:28:04.140 回答