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