C - 发送 UNIX 流套接字中的MSG_MORE对对等方的接收无效



以下是有关我遇到的问题的一些背景:

我有一个流server_fd = socket(AF_UNIX, SOCK_STREAM, 0)类型的 unix 套接字。在服务器端,套接字通过listen(server_fd, 128)listen(2),并绑定到处理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字节。

更多信息:

  • 套接字是非阻塞的(O_NONBLOCK),允许地址重用(SO_REUSEADDR设置为1)。
  • 太阳之路"/tmp/test-socket".
  • bind(2)用于将套接字绑定到服务器端的 Sunpath,connect(2)用于客户端
  • SO_RCVBUFSO_SNDBUF都设置为 1 MB
  • 我将调试放在服务器和客户端。我什至确保在客户端尝试读取任何内容之前发送所有数据部分。尽管如此,同样的问题还是发生了。

更新

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

从 linuxunix(7)手册页:

UNIX 域套接字不支持send(2)MSG_MORE标志。

并且还感兴趣:

SO_SNDBUF套接字选项对 UNIX 域套接字有影响,但SO_RCVBUF选项不起作用。


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

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

相关内容

最新更新