Linux套接字:零拷贝本地,TCP / IP远程

networking是我在操作系统中最糟糕的地方,请原谅我问一个不完整的问题。 我已经阅读了几个小时,但它有点儿在我的脑海里游泳。 (对于我来说,我觉得与找出networking协议相比,芯片devise很容易。)

我有一些通过套接字相互通信的networking服务。 具体来说,套接字使用fd = socket(PF_INET, SOCK_STREAM, 0); ,它会自动获取TCP / IP。 我需要这个作为基础的情况下,因为这些服务可能运行在不同的机器上。

但是对于一个项目,我们试图把所有这些都embedded到基于Atom Z530P的embedded式“设备”中,所以在我看来,内存复制开销是我们可以优化的。 我一直在这里读到: data-link-access-and-zero-copy和Linux_packet_mmap和packet_mmap 。

对于这种情况,可以创build如下所示的套接字: fd = socket(PF_PACKET, PF_RAW, 0); 。 还有一些其他的东西可以做,比如分配环形缓冲区,映射它们,将它们和套接字关联起来等等。看起来像限制使用sendtorecvfrom来传输数据。 据我所知,由于套接字是本地的,你不需要一个可靠的“stream”types套接字,所以原始套接字是适当的接口,我环形缓冲区是在页面粒度使用,其中每个数据包(或数据报)从页面边界开始。

在我花费大量时间来进一步调查之前,我希望有些有用的人可以帮我解决一些问题:

  • 我应该从零拷贝套接字中获得多less性能好处? 我想最后一次检查,我们正在从一个进程到另一个进程移动最大的40 MB /秒,最后到磁盘。 在最基本的情况下,数据从捕获进程转移到一对多进程(其他进程可以在stream上侦听)到写入磁盘的归档进程。 这是不计算磁盘和内部的东西的两跳。
  • Linux是否会自动执行这些操作,为在同一台机器上运行的进程进行优化?
  • 无论如何,我会在TCP端口侦听套接字。 我可以使用这些进程之间的连接,但仍然能够使用零拷贝? 换句话说,我可以在PF_PACKET中使用AF_INET吗?
  • 带有SOCK_RAW的PF_PACKET是零拷贝套接字的唯一有效configuration吗?
  • 是否有任何好的示例代码将使用零拷贝与TCP / IP作为后备?
  • 检测这两个进程在同一台机器上的最简单或最好的方法是什么? 他们知道彼此的IP地址,所以我可以比较和使用不同的代码path。 有一个更简单的方法来做到这一点?
  • 我可以在基于包的套接字上使用write()和read(),还是只对stream有效? (重写连接的方式会更简单,然后重写所有的套接字代码。)
  • 我过分复杂的事情和/或优化错误的东西? OProfiler告诉我,大部分CPU时间花费在两个地方:(1)zlib,(2)内核,由于我使用的CentOS 6.2不提供vmlinux,所以我无法进行configuration。 我假设内核时间是空闲时间和数据复制的组合,而不是其他的。

先谢谢您的帮助!

我过分复杂的事情和/或优化错误的东西?

有可能。 使用PF_PACKET套接字只适用于专门的东西。 你可能想看看

  • 的sendfile(2)
  • 拼接(2)

检测这两个进程在同一台机器上的最简单或最好的方法是什么?

根本不要“忘记”这些信息。

Linux是否会自动执行这些操作,为在同一台机器上运行的进程进行优化?

不,你必须自己做。

我认为TCP / IP和原始数据包之间的选择比零拷贝问题重要得多。 如果您需要可靠的基于流的通信,则需要TCP / IP(即AF_INET + PF_STREAM)。 试图通过不可靠的数据包实现一个可靠的流是非常复杂的,它已经为你做了。

使用零拷贝和文件的TCP / IP的最佳方式是,像@ cnicutar所说的,sendfile(2)和splice(2)。 我想有一种方法可以在没有这些功能的情况下享受零拷贝(如果你想把数据读入内存,而不是直接写入文件),但是我不确定如何去做。

另外,Centos是开源的,所以你可以通过下载源代码并编译得到一个vmlinux文件。