UNIX域套接字,发送超时,零拷贝

时间:2016-01-13 16:53:34

标签: c linux sockets unix unix-socket

我正在学习UNIX域套接字并尝试一些客户端服务器程序。我正在使用SOCK_DGRAM系列套接字。

我怀疑是:

  1. 在发送和接收时,是否正在使用UNIX域套接字从用户空间复制缓冲区到内核空间缓冲区?
  2. 所以我的电话:

    sendto(send_thread_socket, (void*)argData, sizeof(*argData), 0,
                                            (struct sockaddr *)&dpdkServer, sizeof(struct sockaddr_un))
    

    将缓冲区复制到某个内核空间缓冲区,还是直接复制到接收进程的用户空间缓冲区。由于UNIX套接字在文件系统命名空间上工作,我认为它不应该复制缓冲区。

    1. 由于我使用的是SOCK_DGRAM,发送超时是否有意义?
    2. 假设我使用相同的sendto()调用,但接收方不保证及时收集数据,我可以发送超时。

3 个答案:

答案 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,您可以归档零拷贝数据交换。

但是设置需要很多时间,因此您应该对其进行测量,并且仅当您传输大量数据或者您有内存消耗低的原因时才这样做。请记住,使用简单的复制操作,您将需要三倍的内存。这可能比复制的性能损失更大。