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

时间:2011-12-28 21:15:02

标签: linux sockets zero-copy

网络是我操作系统中最糟糕的区域,所以请原谅我提出一个不完整的问题。我已经读了几个小时这个,但它有点游泳在我脑海里。 (对我而言,与制定网络协议相比,我觉得芯片设计很容易。)

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

但是对于一个项目,我们试图将它们全部压缩到基于Atom Z530P的动力不足的嵌入式“设备”中,因此在我看来,内存复制开销是我们可以优化的。我一直在这里阅读:data-link-access-and-zero-copyLinux_packet_mmap以及packet_mmap

对于这种情况,可以创建类似这样的套接字:fd = socket(PF_PACKET, PF_RAW, 0);。还有很多其他的事情要做,比如分配环形缓冲区,对它们进行映射,将它们与套接字相关联等等。看起来你只能使用sendtorecvfrom来传输数据。据我所知,由于套接字是本地的,你不需要一个可靠的“流”类型套接字,因此原始套接字是适当的接口,而我猜测使用了环形缓冲区在页面粒度,每个数据包(或数据报)从页面边界开始。

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

  • 我期望从零拷贝套接字获得多少性能优势?我想最后一次检查,我们正在将一个40 MB /秒的最大从一个进程移动到另一个进程,最后到磁盘。在最基本的场景中,数据从捕获过程转移到一对多进程(其他人可以监听流),转移到写入磁盘的归档进程。这是两个不计算磁盘和内部数据的啤酒花。
  • Linux是否自动执行此操作,优化在同一台计算机上运行的进程?
  • 在任何情况下,我都会在TCP端口中侦听套接字。我可以使用它们在进程之间建立连接但仍然可以使用零拷贝吗?换句话说,我可以将AF_INET与PF_PACKET一起使用吗?
  • 带有SOCK_RAW的PF_PACKET是零拷贝套接字的唯一有效配置吗?
  • 是否有任何好的示例代码可以使用带有TCP / IP的零拷贝作为后备?
  • 检测这两个进程在同一台机器上的最简单或最好的方法是什么?他们知道彼此的IP地址,所以我可以比较并使用不同的代码路径。有没有更简单的方法呢?
  • 我可以在基于数据包的套接字上使用write()和read(),还是仅对流有效? (重写连接的方式会更简单,然后重写所有套接字代码。)
  • 我是否过度复杂化和/或优化错误的东西? OProfiler告诉我,大多数CPU时间花费在两个地方:(1)zlib,以及(2)内核,我无法分析,因为我使用的是CentOS 6.2,它没有提供vmlinux。我假设内核时间是空闲时间和数据复制的结合,而不是其他。

提前感谢您的帮助!

2 个答案:

答案 0 :(得分:7)

  

我是否过度复杂化和/或优化错误的东西?

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

  

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

不要“忘记”这些信息。

  

Linux是否会自动执行任何操作,优化流程   在同一台机器上运行?

不,你必须亲自去做。

答案 1 :(得分:2)

我认为TCP / IP和原始数据包之间的选择比零复制问题重要得多。如果需要可靠的基于流的通信,则需要TCP / IP(即AF_INET + PF_STREAM)。尝试在不可靠的数据包上实现可靠的流非常复杂,并且已经为您完成了。

使用带有零拷贝和文件的TCP / IP的最佳方法是,如@cnicutar所说,sendfile(2)和splice(2)。我认为有一种方法可以在没有这些的情况下享受零拷贝(如果你想将数据读入内存,而不是直接读取文件),但我不知道该怎么做。

此外,Centos是开源的,因此您可以通过下载源代码并编译它来获取vmlinux文件。