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

Linux套接字:零拷贝本地、TCP/IP远程,linux,sockets,zero-copy,Linux,Sockets,Zero Copy,网络是我操作系统中最糟糕的领域,所以请原谅我问了一个可能不完整的问题。关于这件事我已经读了好几个小时了,但它在我的脑海里游荡。(对我来说,芯片设计比网络协议更容易。) 我有一些通过套接字相互通信的网络服务。具体地说,使用fd=socket(PF_INET,SOCK_STREAM,0)创建套接字,自动获取TCP/IP。我需要将此作为基本情况,因为这些服务可能在不同的机器上运行 但对于一个项目,我们正试图将它们全部压缩到一个基于Atom Z530P的动力不足的嵌入式“设备”中,因此在我看来,内存拷贝

网络是我操作系统中最糟糕的领域,所以请原谅我问了一个可能不完整的问题。关于这件事我已经读了好几个小时了,但它在我的脑海里游荡。(对我来说,芯片设计比网络协议更容易。)

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

但对于一个项目,我们正试图将它们全部压缩到一个基于Atom Z530P的动力不足的嵌入式“设备”中,因此在我看来,内存拷贝开销是我们可以优化的。我一直在这里读到这方面的文章:而且

对于这种情况,可以创建如下套接字:
fd=socket(PF_数据包,PF_原始,0)。还有一大堆其他的事情要做,比如分配环形缓冲区,映射它们,将它们与套接字关联,等等。看起来您只能使用
sendto
recvfrom
来传输数据。据我所知,由于套接字是本地的,您不需要可靠的“流”类型套接字,因此原始套接字是合适的接口,我猜环形缓冲区是在页面粒度上使用的,其中每个数据包(或数据报)从页面边界开始

在我花费大量时间试图进一步调查这一问题之前,我希望一些有帮助的人能帮助我解决一些问题:

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

我是否过度复杂化了事情和/或优化了错误的事情

可能吧。使用
PF_数据包
sockets仅用于专门的东西。你可能想调查一下

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

只是不要“忘记”这些信息

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


不,你必须自己做。

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

如@cnicutar所说,将TCP/IP与零拷贝和零文件一起使用的最佳方法是sendfile(2)和splice(2)。我认为有一种方法可以享受零拷贝而不需要这些(如果您想将数据读入内存,而不是直接读入文件),但我不知道如何做到这一点

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