Protocol-Independent带外数据
流套接字抽象包括带外 (OOB) 数据的概念。 许多协议允许以某种方式将传入数据的某些部分标记为特殊,并且这些特殊数据块可以按正常顺序传递给用户。 示例包括 X.25 和其他 OSI 协议中的加速数据,以及 BSD UNIX 使用 TCP 中的紧急数据。 以下部分以与协议无关的方式介绍 OOB 数据处理。 有关使用 TCP 紧急数据实现的 OOB 数据的讨论遵循与协议无关的说明。 在每个讨论中, recv 的使用还意味着 recvfrom、 WSARecv 和 WSARecvFrom,对 WSAsyncSelect 的引用也适用于 WSAEventSelect。
独立于协议的 OOB 数据
OOB 数据是与每对连接的流套接字关联的逻辑独立传输通道。 OOB 数据可以独立于正常数据传送给用户。 抽象定义 OOB 数据设施必须支持一次至少一个 OOB 数据块的可靠交付。 此数据块可以包含至少一个字节的数据,并且至少有一个 OOB 数据块可以在任何时间等待传递给用户。 对于支持带内信令 (的通信协议(例如 TCP),紧急数据与正常数据) 按顺序传送,系统通常从正常数据流中提取 OOB 数据并将其单独存储, (在正常数据流) 中留出空白。 这使用户可以在按顺序接收 OOB 数据与按顺序接收 OOB 数据之间进行选择,而无需缓冲所有中间数据。 可以扫视带外 (OOB) 数据。
用户可以使用带有 SIOCATMARKIOCTL 的 ioctlsocket 或 WSAIoctl 函数来确定是否正在等待读取任何 OOB 数据。 对于 OOB 数据块在正常数据流中的位置概念有意义的协议(例如 TCP),Windows 套接字服务提供程序维护一个概念标记,该标记指示 OOB 数据的最后一个字节在正常数据流中的位置。 这不是支持 SIOCATMARK 的 ioctlsocket 或 WSAIoctl 函数实现所必需的。 OOB 数据的存在与否都是必需的。
对于 OOB 数据块在正常数据流中的位置概念有意义的协议,应用程序可能会内联处理带外数据,作为正常数据流的一部分。 这是通过使用 setsockopt 函数设置套接字选项SO_OOBINLINE来实现的。 对于 OOB 数据块真正独立于正常数据流的其他协议,尝试设置SO_OOBINLINE会导致错误。 应用程序可以将 ioctlsocket 或 WSAIoctl 函数与 SIOCATMARK IOCTL 结合使用,以确定标记前面是否有任何未读的 OOB 数据。 例如,它可以使用此信息与对等方重新同步,方法是确保适当时丢弃数据流中所有达到标记的数据。
禁用SO_OOBINLINE (默认设置) :
- 如果应用程序注册了 WSAsyncSelect 的通知,Windows 套接字会通知应用程序FD_OOB事件,其方式与使用 FD_READ 通知正常数据的方式完全相同。 也就是说,当 OOB 数据到达且之前没有 OOB 数据排队时,将发布FD_OOB。 在使用 MSG_OOB 标志读取数据时,也会发布FD_OOB,而某些 OOB 数据在读取操作返回后保持排队状态。 不会针对 OOB 数据发布FD_READ消息。
- 如果 OOB 数据在套接字上排队,Windows 套接字将从 select 返回,并设置相应的 exceptfds 套接字。
- 应用程序可以随时使用MSG_OOB调用 recv 来读取紧急数据块。 OOB 数据块将跳转到队列中。
- 应用程序无需MSG_OOB即可调用 recv 来读取正常的数据流。 OOB 数据块不会出现在具有正常数据的数据流中。 如果在对 recv 的任何调用后 OOB 数据仍然存在,Windows 套接字在使用 select 时会以FD_OOB或例外通知应用程序。
- 对于 OOB 数据在正常数据流中的位置的协议,单个 recv 操作不会跨越该位置。 一个 recv 返回标记前的正常数据,需要第二个 recv 才能在标记后开始读取数据。
启用SO_OOBINLINE后:
- 不会针对 OOB 数据发布FD_OOB消息。 对于 select 和 WSAsyncSelect 函数,OOB 数据被视为正常数据,并通过分别在 readfds 中设置套接字或通过发送FD_READ消息来指示。
- 应用程序无法使用设置为读取 OOB 数据块的 MSG_OOB 标志调用 recv 。 返回错误代码 WSAEINVAL。
- 应用程序可以在不设置MSG_OOB标志的情况下调用 recv 。 任何 OOB 数据在正常数据流中按正确的顺序传送。 OOB 数据绝不会与普通数据混合。 必须有三个读取请求才能通过 OOB 数据。 第一个返回 OOB 数据块之前的正常数据,第二个返回 OOB 数据,第三个返回 OOB 数据后面的正常数据。 换句话说,将保留 OOB 数据块边界。
WSAAsyncSelect 例程特别适用于在关闭SO_OOBINLINE时处理带外数据存在的通知。
TCP 中的 OOB 数据
重要
以下讨论使用 TCP 紧急数据实现的带外数据 (OOB) 遵循伯克利软件分发中使用的模型。 用户和实施者应注意:
目前, RFC 793 (有两种相互矛盾的解释,) 引入概念。
在 Berkeley Software Distribution (BSD) 中实现 OOB 数据不符合 RFC 1122 中指定的主机要求。
具体而言,BSD 中的 TCP 紧急指针指向紧急数据字节后面的字节,符合 RFC 的 TCP 紧急指针指向紧急数据字节。 因此,如果应用程序将紧急数据从与 BSD 兼容的实现发送到与 RFC 1122 兼容的实现,接收方读取错误的紧急数据字节 (它读取位于数据流中正确字节之后的字节,因为紧急数据字节) 。
为了尽量减少互操作性问题,建议应用程序编写者不要使用 OOB 数据,除非需要与现有服务互操作。 敦促 Windows 套接字供应商记录其产品实现的 OOB 语义 (BSD 或 RFC 1122) 。
TCP 段的到达与 URG (紧急) 标志集表示 TCP 数据流中存在单个字节的 OOB 数据。 OOB 数据块的大小为一个字节。 紧急指针是 TCP 标头中当前序列号的正偏移量,指示 OOB 数据块的位置 (不明确,如前面的) 中所述。 因此,它可能指向尚未收到的数据。
如果在包含紧急指针指向的字节的 TCP 段到达时禁用SO_OOBINLINE (默认) ,则会从数据流中删除一个字节) 的 OOB 数据块 (并对其进行缓冲。 如果后续 TCP 段到达时 (设置了紧急标志,并且新的紧急指针) ,则当前排队的 OOB 字节可能会丢失,因为它被新的 OOB 数据块 (所取代,如 Berkeley Software Distribution) 中所示。 但是,它永远不会在数据流中被替换。
启用SO_OOBINLINE后,紧急数据将保留在数据流中。 因此,当包含紧急数据的新 TCP 段到达时,OOB 数据块永远不会丢失。 现有 OOB 数据标记将更新到新位置。
注意
设置SO_OOBINLINE套接字选项时,SIOCATMARK IOCTL 始终返回 TRUE,并且 OOB 数据将作为正常数据返回给用户。