sendmsg / recvmsg中的部分读/写问题

时间:2016-07-18 08:15:52

标签: c sockets unix-socket

我正在编写一个程序,通过域套接字使用sendmsgrecvmsg在两个进程之间传递文件描述符。对于发送文件描述符,msghdr.msg_iovmsghdr.msg_iolen中包含其他数据。但是,我被告知与普通readwrite系统调用类似,sendmsgrecvmsg也存在部分读/写问题。在这种情况下,是否会为每个部分数据自动复制辅助字段中的数据?我问这个是因为我的实现需要非阻塞机制。让我用下面的例子再详细说明一下

发件人:发送msghdr数据,其中包含fd的辅助字段和K字节msg_iov

接收方:(1)部分读取,K1字节(2)部分读取,K-K1字节

现在如上例所示,当所有数据到达时,我应该在步骤(2)之后处理数据。在这种情况下,我还能从辅助字段中正确提取fd吗?或者它只出现在第一次部分阅读中?

1 个答案:

答案 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部分已经存在发送。