我正在编写一个程序,通过域套接字使用sendmsg
和recvmsg
在两个进程之间传递文件描述符。对于发送文件描述符,msghdr.msg_iov
和msghdr.msg_iolen
中包含其他数据。但是,我被告知与普通read
和write
系统调用类似,sendmsg
和recvmsg
也存在部分读/写问题。在这种情况下,是否会为每个部分数据自动复制辅助字段中的数据?我问这个是因为我的实现需要非阻塞机制。让我用下面的例子再详细说明一下
发件人:发送msghdr
数据,其中包含fd
的辅助字段和K
字节msg_iov
接收方:(1)部分读取,K1
字节(2)部分读取,K-K1
字节
现在如上例所示,当所有数据到达时,我应该在步骤(2)之后处理数据。在这种情况下,我还能从辅助字段中正确提取fd
吗?或者它只出现在第一次部分阅读中?
答案 0 :(得分:1)
从内核源代码(Linux,但见下文)的快速gander,我相信你需要确保辅助数据只被发送一次。也就是说,在非阻塞模式下,如果接收套接字中没有空间,您将返回EAGAIN
/ EWOULDBLOCK
,并且不会发送数据和辅助数据。但是如果接收方有一些空间,那么将发送数据的初始部分,并且还将发送辅助数据。然后,您将收到一个返回字节计数,表示部分发送,但辅助数据将被发送。
当你尝试发送剩余的消息时,你需要注意这一点,因为内核没有内存,你以前发送过一个部分缓冲区,后续缓冲区在逻辑上是连续的(实际上它没办法 - 你可以为它所知道的所有人发送完全不同的数据。因此,如果您只为后续缓冲区部分提供相同的辅助数据,我相信内核将很乐意再次使用您的后续缓冲区部分提供辅助数据。这可能会导致接收方的文件描述符重复(你可能会忽略它,因为你不会期望它们) - 如果你不避免它。
现在,如果你在发送端处于阻塞模式,并且传输被分成多个部分,辅助数据将只发送一次 - 使用第一个缓冲部分,因为整个缓冲区的发送保持在内核控制。
在接收方,您需要知道,如果您没有收到整个逻辑消息,辅助数据会伴随第一块接收数据。
我认为这种行为与@ Klas-Lindbäck(https://unix.stackexchange.com/questions/185011/what-happens-with-unix-stream-ancillary-data-on-partial-reads)给出的stackexchange引用中报告的行为一致。 (但这个问题并没有涉及非阻塞模式。)
这个答案特定于linux。因此,结果在其他操作系统上的结果肯定会有所不同,尽管我很难看出它们如何显着不同并且仍然保持理智的语义。内核无法合理地维护以前发送的内容,sendmsg
原型不允许它覆盖用户的msghdr
以反映msg_control
部分已经存在发送。