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

4
网络是我在操作系统中最薄弱的领域,所以请原谅我提出可能不完整的问题。虽然我已经阅读了几个小时,但这些知识还是很混乱(对我来说,芯片设计相对于网络协议而言似乎更容易)。
我有一些通过套接字相互通信的网络服务。具体来说,这些套接字是使用fd = socket(PF_INET, SOCK_STREAM, 0);创建的,它自动获得TCP/IP协议。我需要这个作为基本情况,因为这些服务可能在不同的机器上运行。
但对于一个项目,我们正在试图将所有的服务压缩到一个基于Atom Z530P的低功耗嵌入式装置中,所以我认为内存复制开销是我们可以优化的。我在这里阅读了一些关于此的文章:data-link-access-and-zero-copyLinux_packet_mmappacket_mmap
对于这种情况,人们应该像这样创建套接字:fd = socket(PF_PACKET, PF_RAW, 0);。还有一堆其他的事情要做,比如分配环形缓冲区,映射它们,将它们与套接字关联起来等等。看起来你只能用sendtorecvfrom来传输数据。据我所知,由于套接字是本地的,所以不需要可靠的“流”类型套接字,因此原始套接字是适当的接口,而我猜测环形缓冲区是按页面粒度使用的,其中每个数据包(或数据报)从页面边界开始。
在我花费大量时间进一步调查之前,我希望一些乐于助人的人能够回答我的问题:
  • 使用零拷贝套接字,我应该期望获得多少性能提升?最后一次检查时,我们从一个进程移动了最大约40 MB/秒的数据到另一个进程,最终写入磁盘。在最基本的场景中,数据从捕获进程移动到一对多进程(其他人可以监听流),再移动到写入磁盘的归档器进程。这是两个跳跃,不计算磁盘和内部事务。
  • Linux是否会自动进行优化,以适合在同一台机器上运行的进程?
  • 无论如何,我都会有TCP端口的侦听套接字。我可以使用它们来在进程之间建立连接,但仍然能够使用零拷贝吗?换句话说,我可以使用AF_INET和PF_PACKET吗?
  • PF_PACKET与SOCK_RAW是零拷贝套接字的唯一有效配置吗?
  • 是否有任何优秀的示例代码,将TCP/IP作为后备使用零拷贝?
  • 检测两个进程是否在同一台机器上,最简单或最好的方法是什么?它们知道彼此的IP地址,所以我可以进行比较并使用不同的代码路径。是否有更简单的方法来做到这一点?
  • 我可以在基于数据包的套接字上使用write()和read(),还是仅适用于流?(重新编写连接方式比重新编写所有套接字代码更简单。)
  • 我是否过于复杂化并/或优化了错误的方面?OProfiler告诉我,大多数CPU时间都花费在两个地方:(1)zlib和(2)内核,由于我正在使用CentOS 6.2,它不提供vmlinux,因此无法对内核进行性能分析。我认为内核时间是空闲时间和数据复制的组合,除此之外没有其他。

非常感谢您的帮助!

2个回答

7

我是否过于复杂化事情和/或优化了错误的东西?

可能是。使用PF_PACKET套接字仅用于专业的事情。您可能需要研究以下内容

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

简单地不要“忘记”这些信息。

Linux是否会自动执行任何此操作,以优化在同一台计算机上运行的进程?

不,您必须自己完成。


2
我认为在TCP/IP和原始数据包之间的选择比零拷贝问题更重要。如果您需要可靠的基于流的通信,则需要TCP/IP(即AF_INET+PF_STREAM)。尝试在不可靠的数据包上实现可靠的流非常复杂,而且这已经为您完成了。
使用零拷贝和文件的最佳方式是,如@cnicutar所说,使用sendfile(2)和splice(2)。我认为有一种方法可以在没有这些情况下享受零拷贝(如果您想将数据读入内存,而不是直接读入文件),但我不确定如何做到这一点。
此外,Centos是开源的,因此您可以通过下载源代码并编译来获得vmlinux文件。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接