我正在学习UNIX域套接字并尝试一些客户端服务器程序。我正在使用SOCK_DGRAM系列套接字。
我怀疑是:
所以我的电话:
sendto(send_thread_socket, (void*)argData, sizeof(*argData), 0,
(struct sockaddr *)&dpdkServer, sizeof(struct sockaddr_un))
将缓冲区复制到某个内核空间缓冲区,还是直接复制到接收进程的用户空间缓冲区。由于UNIX套接字在文件系统命名空间上工作,我认为它不应该复制缓冲区。
假设我使用相同的sendto()调用,但接收方不保证及时收集数据,我可以发送超时。
答案 0 :(得分:2)
函数sendto
不会等待收件人在返回之前收到数据。所以,是的,要实现这一点,数据将被复制到内核拥有的缓冲区,然后通过接收过程再次复制出来。
为什么:如果不是这种情况,那么两个进程交换消息或多或少都是不可能的。如果进程P1尝试向进程P2发送消息,则在P2调用read
之前它将不会成功。如果P2当时正试图向P1发送一个消息,那么在P1调用read
之前它不会成功。但P1正在等待sendto
的阻止调用。这些过程将陷入僵局。
内核缓冲是该问题的解决方案。
答案 1 :(得分:1)
Ben很好地涵盖了主要方面,但这里也有其他的东西。
让我们说我们将允许对域套接字进行零拷贝,让我们说允许sendto()阻塞,直到调用recvfrom()来远离内核缓冲区。我看到内核的速度非常快 - 我们必须将该页面转移到接收过程中(这意味着它最好是一整页),而且,如果一切都没有完全执行,那么无论如何都要获得副本。由于显而易见的原因,发件人无法调用free()或重新使用缓冲区,因为这会强制执行pagefault-copy。
丑陋,只是丑陋。没有人会费心去写所有这些因为难以使用的东西。唯一足以保证的unix域套接字用户是X,而X并不保证消息大小允许这样做。
答案 2 :(得分:0)
我只想补充一点,如果您交换的数据足够大和/或足够频繁以进行优化,那么您可以通过 create_memfd
系统调用创建一个匿名文件并将文件描述符与您的消息一起传递。如果您在此临时文件上使用 mmap
,您可以归档零拷贝数据交换。
但是设置需要很多时间,因此您应该对其进行测量,并且仅当您传输大量数据或者您有内存消耗低的原因时才这样做。请记住,使用简单的复制操作,您将需要三倍的内存。这可能比复制的性能损失更大。