【问题标题】:zero copy udp socket using sendfile instead of sendto使用 sendfile 而不是 sendto 的零复制 udp 套接字
【发布时间】:2017-04-06 09:24:42
【问题描述】:

我正在实时环境中使用 udp 套接字。我目前正在使用标准套接字函数 sendto() ,这需要相当多的时间。我读到可以使用零复制,如果我理解得很好,可以避免通过从用户/内核环境复制文件来增加额外的时间。但是,我看到sendfile() 只允许从一个文件描述符复制到另一个文件描述符。我看不出如何使用它来发送 UDP 数据包,在我的例子中是一个缓冲区。所以我的问题是:

  1. 甚至可以使用 sendfile() 发送 UDP 数据包吗?
  2. 如果是这样,正确的做法是什么?

编辑

我正在一个实时平台上工作,我有几个操作以及通过套接字发送。所有这些都不应超过 1ms。我在三台机器上试过,第一台有 4 核 3.4GHz,其他 8 核 2.3GHz,最后一台 4 核 1.4GHz。在第一个上,发送一个 720 字节的数据包需要不到 1µs 的时间。而在另外两个上,它在 6 到 9µs 之间。我使用的是 linux 低延迟内核,并停用了所有 CPU 电源管理功能,因此所有 CPU 都处于最大频率。

我注意到,如果 sendto() 所用的时间大于 6µs,则平台根本无法工作。另一种精度,我有几个线程并行运行。所以也许只是 CPU 处理其他线程,而 sendto() 还没有完成。我想知道这是可能的,在进行其他操作时停止 sendto() 。

这就是为什么我试图寻找其他解决方案在其他地方进行优化,我认为使用 sendfile() 可以避免额外的时间被保存。

【问题讨论】:

  • 在 Linux(以及 Unixy 世界的其他部分)中,什么是“套接字”?它是一个描述符。仅仅因为一些文档说“文件”描述符并不意味着它必须是一个实际的“文件”。否则整个 sendfile 调用将毫无用处,如果它只能复制文件。
  • @Someprogrammerdude。谢谢你。我对描述符/指针/...之间的区别不太熟悉。在我的情况下,我有一个缓冲区,其中包含我要发送的数据包。如果我理解,它不被视为与描述符相同,因此无法直接将其传递给 sendfile();对吗?
  • 不,sendfile 仅在描述符之间复制。如果源是内存缓冲区,则不能使用它。然后你必须使用sendto
  • @Someprogrammerdude。谢谢你。是否有另一种方法可以最大限度地减少套接字 sendto 所花费的时间?
  • 阅读您为sendfile() 提供的文档链接我怀疑它是否可以在UDP 上可靠地工作,如果它完全可以工作的话。提到了 TCP,它是一种面向连接的流,而 UDP 是一种无连接的数据包协议。所以 TCP 的语义有点像顺序文件,而 UDP 没有。

标签: c linux sockets


【解决方案1】:

我不确定sendfile 是否适用于 UDP 套接字,但是,memfd_create 从内存中创建一个文件描述符,理论上可以绕过从用户空间复制到内核。

尽管如此,发送时内核必须首先将数据复制到内核套接字缓冲区,因为它需要在用户数据前添加 UDP、IP 和以太网标头,而这无法就地完成。即使使用sendfile,也无法避免这种复制。

要进行真正的零拷贝网络,您不妨看看PF_RING ZC (Zero Copy) 驱动程序:

使用 PF_RING 感知驱动程序的按需内核绕过

PF_RING™ ZC 带有新一代 PF_RING™ 感知驱动程序,可在内核或旁路模式下使用。安装后,驱动程序作为标准 Linux 驱动程序运行,您可以在其中进行正常网络(例如 ping 或 SSH)。从 PF_RING™ 使用时,它们比普通驱动程序更快,因为它们直接与之交互。如果您在零拷贝中使用 PF_RING 感知驱动程序(例如 pfcount -i zc:eth1)打开设备,则该设备将无法用于标准网络,因为它是通过内核绕过以零拷贝方式访问的,就像以前的 DNA 一样。一旦访问设备的应用程序关闭,标准的网络活动就可以再次发生。

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 2015-07-27
    • 2011-09-05
    • 1970-01-01
    • 2019-08-01
    • 2011-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多