【问题标题】:reading from tcp socket in c, and chucking data without being copied to user space从 c 中的 tcp 套接字读取,并在不复制到用户空间的情况下抓取数据
【发布时间】:2013-08-06 02:37:35
【问题描述】:

当我可以读取套接字缓冲区而不实际读取它时,有一个 peek 选项(以了解可用于后续读取的字节数)。 fcntl 调用有这样的选择。

我想知道是否有一种方法可以在不将数据从套接字复制到应用程序缓冲区的情况下从套接字缓冲区中实际读取?因此,如果您愿意,可以迷惑内核:目的是在设计诸如在 Web 服务器上创建负载的工具时,不要浪费时间复制实际数据:我们需要正确进行 tcp 通信,但我们不需要数据已收到。有什么建议吗?

【问题讨论】:

  • 也许您正在寻找零拷贝技术。在这种情况下,与您的操作系统相对应的标签会很有帮助en.wikipedia.org/wiki/Zero-copy
  • @Kira 感谢您的提示。虽然这不是我的想法(它在内核和用户空间之间进行实际数据复制 - 只是不涉及 CPU,而我对用户空间中的数据不感兴趣) - 它仍然比 recv。知道 gnu linux 是否允许这样做吗?
  • 这样的工具是无效的。如果您想测试负载下的行为,您必须测试所有内容,而不仅仅是您喜欢的部分。

标签: c linux web tcp


【解决方案1】:

man tcp 是你在 Linux 系统上的朋友:

从 2.4 版开始,Linux 支持在 flags 中使用 MSG_TRUNC recv(2)(和 recvmsg(2))的参数。该标志导致收到 要丢弃的数据字节,而不是在调用者提供的缓冲区中传回。

因此,例如,您可以(在 TCP 套接字上)这样做,

   int n = recv(sock_fd, buf, buf_size, MSG_TRUNC);

这将消耗来自套接字描述符sock_fdbuf_size 字节,而不会实际将它们复制到缓冲区。

【讨论】:

    【解决方案2】:

    使用带有MSG_PEEK 标志的recv 系统调用。

    【讨论】:

    • 这不是我要问的
    【解决方案3】:

    这个答案本来是一个评论,但对于恕我直言的评论来说太大了。

    是的,使用splice(2) 会提高性能(当然,如果这是您的瓶颈)(您确定这是您的瓶颈吗?)。尽管splice(2) 是Linux 特定的系统调用,不应该在可移植程序中使用。所以让我们看看你的一些选择:

    1. splice(2) 非常高效但不便携。
    2. sendfile(2) 系统调用更便于移植,但原型因 UNIX 系统而异。
    3. 为多个操作系统创建一个包装函数。
    4. 使用 libevent。

    IMO 你应该使用 libevent,它提供了一个很好的跨平台可移植的接口。

    【讨论】:

    • sendfile 很好,我看不出splice 有什么额外的好处。
    【解决方案4】:

    浏览 Kira 提出的提示让我了解了带有 /dev/null 目标的 splice() 调用。现在应该做:-)

    【讨论】:

    • 它没有。请不要下结论。可能是 NIC 不支持 DMA 和其他数百万种东西。我使用单个 getpagesize() 的缓冲区大小进行了 socket-to-pipe 和 pipe-to-/dev/null 拼接调用
    猜你喜欢
    • 1970-01-01
    • 2014-06-11
    • 1970-01-01
    • 1970-01-01
    • 2019-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多