Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C Linux有零拷贝吗?拼接还是发送文件?_C_Linux_Zero Copy - Fatal编程技术网

C Linux有零拷贝吗?拼接还是发送文件?

C Linux有零拷贝吗?拼接还是发送文件?,c,linux,zero-copy,C,Linux,Zero Copy,当引入splice时,内核列表中讨论了sendfile是基于splice重新实现的。拼接片移动状态的文档: 尝试移动页面而不是复制。这是 只给内核一个提示:页面可能仍然是 如果内核无法从中移动页面,则复制 管道,或者如果管道缓冲区未引用 整页。该计划的初步实施 标志有缺陷:因此从Linux2.6.21开始 这是一个禁止操作(但在 splice()调用);在未来,一个正确的 可以恢复执行 那么,这是否意味着Linux没有用于写入套接字的零拷贝方法?或者这在某个时候是固定的,多年来没有人更新文档?s

当引入splice时,内核列表中讨论了sendfile是基于splice重新实现的。拼接片移动状态的文档:

尝试移动页面而不是复制。这是 只给内核一个提示:页面可能仍然是 如果内核无法从中移动页面,则复制 管道,或者如果管道缓冲区未引用 整页。该计划的初步实施 标志有缺陷:因此从Linux2.6.21开始 这是一个禁止操作(但在 splice()调用);在未来,一个正确的 可以恢复执行

那么,这是否意味着Linux没有用于写入套接字的零拷贝方法?或者这在某个时候是固定的,多年来没有人更新文档?sendfile或splice在最新的3.x内核版本中是否有零拷贝实现


由于谷歌对这个问题没有答案,我正在为下一个可怜的笨蛋创建一个stackoverflow问题,他想知道使用VMPLICE和splice或sendfile是否有任何好处,而不是简单的旧书写方式。

根据splice截至2014-07-08的相关手册页,我引用:

虽然我们谈论复制,但通常避免实际复制。内核通过将管道缓冲区实现为一组指向内核内存页的引用计数指针来实现这一点。内核通过创建引用页面的新指针(用于输出缓冲区)并增加页面的引用计数,在缓冲区中创建页面的“副本”:只复制指针,不复制缓冲区的页面


因此,是的,在大多数情况下,拼接被记录为当前零拷贝。

sendfile
此后一直是零拷贝,并且仍然是零拷贝(假设硬件允许,但通常是这样)。零拷贝是拥有这个系统调用的首要目的
sendfile
现在被实现为
splice
的包装器

这表明,
拼接
也是零拷贝,事实确实如此。至少在理论上,至少在某些情况下。问题在于如何正确使用它,使其可靠工作,从而实现零拷贝。文档是。。。至少可以说是稀疏的

特别是,
splice
仅在页面作为“礼物”赠送时才起到零拷贝的作用,即您不再拥有这些页面(形式上,但实际上您仍然拥有)。如果您只是将文件描述符拼接到套接字上,那么这不是问题,但是如果您希望将数据从应用程序的地址空间或从一个管道拼接到另一个管道,那么这是一个大问题。现在还不清楚之后该如何处理这些页面(以及何时处理)。文档中规定,您以后不得触摸页面或对页面进行任何操作,永远不得。因此,如果按照文档中的字母进行操作,则必须泄漏内存。
这显然是不正确的(不可能),但没有好的方法知道(至少对你来说!)何时可以安全地重用或释放内存。执行
sendfile
的内核会知道,因为一旦它接收到TCP ACK,它就知道不再需要数据。问题是,你永远看不到ACK。当
splice
返回时,您只知道数据已被接受发送(但您不知道它是否已被发送或接收,也不知道这将在何时发生)。
这意味着您需要在应用程序层上以某种方式解决这个问题,或者通过手动确认(通过可靠的UDP免费提供),或者假设如果另一方对您的请求发送响应,那么他们显然一定已经收到了请求

您必须管理的另一件事是有限的管道空间。默认值非常小,但即使增加大小,也不能简单地拼接任何大小的文件<另一方面,code>sendfile只允许您这样做,这很酷

总之,
sendfile
很好,因为它可以正常工作,而且工作良好,您不需要关心上面的任何细节。这不是万灵药,但确实是一个很好的补充。
我个人会远离
splice
及其家族,直到整个事情彻底检修,直到100%清楚你必须做什么(以及什么时候)和不必做什么


无论如何,对于大多数应用程序来说,与普通的
写操作相比,真正有效的收益微乎其微。我记得几年前Torvalds先生的一些不太礼貌的评论(当时BSD有一种
write
的形式,可以通过重新映射页面来获得零拷贝,而Linux没有),其中指出复制通常没有任何问题,但玩页面的把戏[在这里不会重复]。

,但可能相关:我对slice不太了解,但如果你对零拷贝套接字特别感兴趣,你应该看看内存映射套接字:在“注释”下,
splice(2)
manpage说“虽然我们谈论拷贝,但通常避免实际拷贝。”因此,如果可能的话,很可能是零拷贝,但是如果内核不能实现零拷贝,那么它就不会出错。下面解释一下为什么它不是零拷贝:@Eloff:闪闪发光的新AF_XDP实现了原始数据包的真正零拷贝,使用了从Infiniband(RDMA)和DPDK借鉴的思想。Torvalds:“我声称Mach人(显然是FreeBSD)都是不称职的白痴。用虚拟机玩游戏很糟糕。内存拷贝也很糟糕,但坦率地说,内存拷贝的负面影响通常比虚拟机游戏小,更大的缓存只能继续让这一点变得更清楚。”@Ben:是的,这是引用:-)我已经实现了VMPLICE,并使用赠品页面和ack拼接在过去的垃圾收集中,应用程序级ACK,而不是TCP ACK。这很棘手,有很多GOCHAs(这让我),你可以指望它在PLA上添加大约500行C++。