MSG_MORE unix stream socket send 对 peer 的 recv 无效

MSG_MORE in send of unix stream socket is not effective on the peer's recv

以下是关于我遇到的问题的一些背景信息:

我有一个流类型的 unix 套接字 server_fd = socket(AF_UNIX, SOCK_STREAM, 0)。在服务器端,套接字通过 listen(server_fd, 128) listen(2)ed 并绑定到处理 EPOLLIN 的 epoll 处理程序。从所述套接字读取时(使用 epoll 回调),我使用 accept(2) 为绑定到其自己的 epoll 处理 EPOLLIN | EPOLLOUT | EPOLLHUP | EPOLLERR 客户端 创建一个新套接字.到目前为止相当标准。

问题是:

由于服务器端的数据分散在多个来源,目的是让客户端以整齐的方式获取数据,所以我按照这样的要点做了一些事情:

void **data_portions = NULL;
size_t *sz_data_portions = NULL;
size_t cnt_data_portions = 0;
/// ... Fill the variables above based on the needs
fill_data(&data_portions, &sz_data_portions, &cnt_data_portions);
for (size_t i = 0; i < cnt_data_portions; i++) {
    int flags = 0;
    if (i < cnt_data_portions - 1) {
        flags = MSG_MORE;
    }
    send(fd_peer, data_portions[i], sz_data_portions[i], flags);
}

高效地,服务器一个接一个地发送 data_portions 个带有标志 MSG_MORE 的内容,除了最后一个没有标志的内容。可以说,服务器成功发送了所有数据。

现在假设具体情况,即cnt_data_portions = 2sz_data_portions = {128, 32}。这意味着有两次调用 send(2)。第一个 len = 128flags = MSG_MORE,第二个 len = 32flags = 0.

因为我在第一次调用时使用了 MSG_MORE,在客户端,我希望能够使用 recv(2) 一次性读取 128 + 32 = 160 个字节。但是,客户端只能从套接字中读取 128 字节。这违背了 MSG_MORE 的精神。我不明白为什么客户端不能一次读取所有 160 个字节。

更多信息:

更新

我尝试 sendMSG_MORE 的原因是我想将来自不同来源的数据收集到一条消息中。为此,我切换到 sendmsg.

来自linux unix(7) man page:

The send(2) MSG_MORE flag is not supported by UNIX domain sockets.

也很感兴趣:

The SO_SNDBUF socket option does have an effect for UNIX domain sockets, but the SO_RCVBUF option does not.


所以在你的代码中使用 MSG_MORE 是没有意义的;它用于 TCP 和 UDP 套接字。

此外,流(无论是 TCP 套接字、UNIX 域套接字、管道等)的读取次数与远端的写入次数无关。您必须在使用流的更高级别的协议中包含诸如消息边界之类的内容。如果这样做是个问题,您可能会查看 SOCK_SEQPACKET unix 套接字,结合 writev(2) 发送分散数据(我 认为 这会导致所有数据在一个数据包中)。