当前位置: 首页 > 编程日记 > 正文

[转] splice系列系统调用

关注splice系列系统调用(包括splice,tee和vmsplice)已经有一段时间了,开始的时候并未能领会splice的意义所在,致使得出了“splice系列系统调用不怎么实用”的错误结论。随着内核研究的深入,才逐渐懂得:splice对于其中一个文件描述符必须是管道的要求并不是阻碍其应用的障碍,并且恰恰相反,它正是splice的本质所在。

splice 主要通过去除在内核空间和用户空间之间的内存拷贝的开销来提高系统的性能。它将内核空间和用户空间之间的内存拷贝转变成内核空间和内核空间的内存的拷贝, 这样的话,内核就有机会通过底层的一些机制来避免非必要的拷贝,如通过页面的引用来替换拷贝内存页面。这就引出一个问题:内核空间的缓冲区如何在用户空间 表示?恰巧管道符合这个要求,所以就“勉强”让它来担此重任了。因此,当管道被用来做splice的时候,它队列的概念就被弱化了,这时它代表的就是内核 空间的内存缓冲区。因此有了以下几种对应关系:

  • splice(infd,... pipe,...): 从由infd指向的文件读取数据到由pipe指向的内核缓冲区。
  • splice(pipe,... outfd,...): 把由pipe指向的内核缓冲区中的数据写到由oufd指向的文件。
  • tee(inpipe, outpipe,...): 从由inpipe指向的内核缓冲区“拷贝”数据到由outpipe指向的内核缓冲区。
  • vmsplice(rdpipe, iov...): 从由rdpipe(pipe的读端)指向的内核缓冲区“拷贝”数据到由iov表示的用户缓冲区。
  • vmsplice(wrpipe, iov...): 从由iov表示的用户缓冲区“拷贝”数据到由wrpipe(pipe的写端)指向的内核缓冲区。

可见,splice, tee和vmsplice涵盖了在用户空间控制内核缓冲区的全部情况。应该说,已经很完美了。

不过请稍等一下,如果有需要在两个文件之间“拷贝”数据呢?也许我们不得不这样:

  1. splice(fd, ...pipe, ...)
  2. splice(pipe, ...fd, ...)

真 的有必要进行两次系统调用么?事实上两次调用可以合而为一,只在内核内部进行上述操作就行了,因为splice原本就只有在文件和内核缓冲区之间移动数据 的意思,并且在两个文件描述符之间移动数据的API原本就有:sendfile。但是,用sendfile也不是尽善尽美的,sendfile多少有些词 不达意,我想这也可能是它在2.6.9之后就只能用于通过socket接口发送支持mmap系统调用的文件的原因之一。

有了sendfile的加入,这个世界又朝着完美更近了一步。

我们经常听到的一句话就是:前途是美好的,道路是曲折的。

之于splice系列系统调用的实现,这也是成立的,前进的道路上难免会由一些困难和反复,因为这个世界是如此的复杂。

splice系列系统调用首次亮相于2.6.17版内核,直到现在,其实现离完美还有很大一段距离,还有一些问题:

  • splice的套接字读实现存在潜在的数据污染(data corruption)。
  • vmsplice当标志位SPLICE_F_GIFT被设置的时候,其内存地址和大小必须是按页对齐的,缺乏灵活性。这导致不能发送非整页的数据,即使以mmap, splice, munmap的顺序组织系统调用也不可以。
  • sendfile系统调用因为把数据的移动过程在内部分成了从输入文件读取数据到pipe的内核缓冲和从pipe的内核缓冲写数据到输出文件两步,并且两步因为其实现的缘故,必须在原子操作内完成,所以,输出操作必须是阻塞的,极大地限制了其灵活性。

祝splice系列系统调的实现能尽快完美!

1. splice函数

#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);


splice用于在两个文件描述符之间移动数据, 也是零拷贝。

fd_in参数是待输入描述符。如果它是一个管道文件描述符,则off_in必须设置为NULL;否则off_in表示从输入数据流的何处开始读取,此时若为NULL,则从输入数据流的当前偏移位置读入。

fd_out/off_out与上述相同,不过是用于输出。

len参数指定移动数据的长度。

flags参数则控制数据如何移动:

  • SPLICE_F_NONBLOCK:splice 操作不会被阻塞。然而,如果文件描述符没有被设置为不可被阻塞方式的 I/O ,那么调用 splice 有可能仍然被阻塞。
  • SPLICE_F_MORE:告知操作系统内核下一个 splice 系统调用将会有更多的数据传来。
  • SPLICE_F_MOVE:如果输出是文件,这个值则会使得操作系统内核尝试从输入管道缓冲区直接将数据读入到输出地址空间,这个数据传输过程没有任何数据拷贝操作发生。

2. 使用splice时, fd_in和fd_out中必须至少有一个是管道文件描述符。

调用成功时返回移动的字节数量;它可能返回0,表示没有数据需要移动,这通常发生在从管道中读数据时而该管道没有被写入的时候。

失败时返回-1,并设置errno


3. 代码:通过splice将客户端的内容读入到管道中, 再从管道中读出到客户端,从而实现高效简单的回显服务。整个过程未执行recv/send,因此也未涉及用户空间到内核空间的数据拷贝。

//使用splice实现的回显服务器
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>int main(int argc, char **argv)
{if (argc <= 2) {printf("usage: %s ip port\n", basename(argv[0]));return 1;}const char *ip = argv[1];int port = atoi(argv[2]);struct sockaddr_in address;bzero(&address, sizeof(address));address.sin_family = AF_INET;address.sin_port = htons(port);inet_pton(AF_INET, ip, &address.sin_addr);int sock = socket(PF_INET, SOCK_STREAM, 0);assert(sock >= 0);int reuse = 1;setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));assert(ret != -1);ret = listen(sock, 5);assert(ret != -1);struct sockaddr_in client;socklen_t client_addrlength = sizeof(client);int connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength);if (connfd < 0) {printf("errno is: %s\n", strerror(errno));}else {int pipefd[2];ret = pipe(pipefd);  //创建管道assert(ret != -1);//将connfd上的客户端数据定向到管道中ret = splice(connfd, NULL, pipefd[1], NULL,32768, SPLICE_F_MORE | SPLICE_F_MOVE);assert(ret != -1);//将管道的输出定向到connfd上ret = splice(pipefd[0], NULL, connfd, NULL,32768, SPLICE_F_MORE | SPLICE_F_MOVE);assert(ret != -1);				close(connfd);}close(sock);return 0;
}

转载于:https://www.cnblogs.com/qiangxia/p/4740060.html

相关文章:

嵌入式s5vp210裸机 KXTF9-2050(G-sensor)

1.KXTF9-2050简介 KXTF9-205是G-sensor的一种&#xff0c;G-sensor&#xff08;Gravity sensor&#xff09;&#xff0c;重力传感器&#xff0c;又名加速度传感器&#xff08;accelerometer&#xff09;&#xff0c;是能感知加速度大小的MEMS(微机电系统)传感器。使用I2C协议和…

JavaScript面向对象编程

自从有了Ajax这个概念&#xff0c;JavaScript作为Ajax的利器&#xff0c;其作用一路飙升。JavaScript最基本的使用&#xff0c;以及语法、浏览器对象等等东东在这里就不累赘了。把主要篇幅放在如何实现JavaScript的面向对象编程方面。1. 用JavaScript实现类 JavaScritpt没…

sublime text3 前端插件介绍

Emmet插件 Emmet插件可以说是使用Sublime Text进行前端开发必不可少的插件 它让编写HTML代码变得极其简单高效 基本用法&#xff1a;输入标签简写形式&#xff0c;然后按Tab键 关于Emmet的更多介绍&#xff0c;请查看官方文档 这份速查表&#xff0c;可以帮你快速记忆简写形式 …

如何使用 OpenCV Python 检测颜色

作者 | 小白来源 | 小白学视觉在这篇文章中&#xff0c;我们将看到如何使用 Python 中的 OpenCV 模块检测颜色&#xff0c;进入这个领域的第一步就是安装下面提到的模块。pip install opencv-python pip install numpy然后&#xff0c;导入模块。读取图像并使用 OpenCV 模块中的…

使用树形结构保存实体

阅读原文请访问我的博客BrightLoongs Blog之前在项目需要实现一个功能——将xml文件映射成实体&#xff0c;然后对映射的实体进行逻辑处理&#xff0c;最后保存到数据库中&#xff1b;由于xml结构的数据是结构化的数据&#xff0c;所以需要保证保存的数据具有正确的主外键关联。…

在Javascript中使用面向对象的编程

by Mike Koss March 26th, 2003 这是一篇&#xff0c;我个人认为最好的&#xff0c;Javascript面向对象编程的文章。翻译不好的地方&#xff0c;还望大家指正&#xff0c;谢谢。 如果您需要&#xff0c;可以访问下面的地址取得原文&#xff1a; http://mckoss.com/jscript/obj…

马斯克嘲笑「元宇宙」的想法,并给年轻人5条鸡汤

编译 | 禾木木出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;SpaceX 和特斯拉的CEO 马斯克在接受 The Babylon Bee 的采访中&#xff0c;当被问到元宇宙的问题时&#xff0c;马斯克只笑了笑。马斯克表示&#xff1a;“我对元宇宙这个概念没有什么印象&#xff0c;尽…

OpenLDAP自定义属性的启用

2019独角兽企业重金招聘Python工程师标准>>> # ucode# This multivalued field is used to record the values of the license or# registration plate associated with an individual.attributetype ( 2.16.840.1.113730.3.1.900 NAME ucode DESC user code …

硬中断与软中断的区别!

硬中断&#xff1a; 1. 硬中断是由硬件产生的&#xff0c;比如&#xff0c;像磁盘&#xff0c;网卡&#xff0c;键盘&#xff0c;时钟等。每个设备或设备集都有它自己的IRQ&#xff08;中断请求&#xff09;。基于IRQ&#xff0c;CPU可以将相应的请求分发到对应的硬件驱动上&am…

smarty模板

<?phprequire(../libs/Smarty.class.php);$smarty new Smarty;//$smarty->force_compile true;//$smarty->debugging true;//$smarty->caching true;//$smarty->cache_lifetime 120;$Name"Linux环境高级编程";$smarty->assign("name&qu…

乘“云原生”之风、踏“数字化”的浪,《新程序员003》开启预售!

12月30日&#xff0c;新年的钟声还有两天敲响&#xff0c;CSDN倾情策划出品的《新程序员003&#xff1a;云原生和全面数字化实践》&#xff08;以下简称《新程序员003》&#xff09;重磅开启预售&#xff01;新一年&#xff0c;新气象~预祝所有开发者在新的一年中大神附体&…

BZOJ4245 : [ONTAK2015]OR-XOR

按位考虑&#xff0c;逐步确定答案。 设当前是第i位&#xff0c;求出第i位的前缀异或和。 若存在m个0且所有数字异或和为0&#xff0c;那么答案的这一位可以为0&#xff0c;并把所有1的位置给标记为不可选。 否则答案的这一位只能是1。 时间复杂度$O(n\log n)$。 #include<c…

关键词排名下降怎么办-优八学院给你支招

优八学院下面为大家解决一下关于关键词排名下降的问题。在我们进行网站优化的时候&#xff0c;往往会出现关键词排名下降的现象。对于这种情况&#xff0c;我们要区别是否是正常的浮动&#xff0c;由于有时候搜索引擎也会发生错误&#xff0c;导致关键词排名下降&#xff0c;我…

全面解析 Kmeans 聚类算法(Python)

作者 | 泳鱼来源 | 算法进阶一、聚类简介Clustering (聚类)是常见的unsupervised learning (无监督学习)方法&#xff0c;简单地说就是把相似的数据样本分到一组&#xff08;簇&#xff09;&#xff0c;聚类的过程&#xff0c;我们并不清楚某一类是什么&#xff08;通常无标签信…

.htaccess的重写规则

.htaccess基本语法和应用 .htaccess是Apache服务器的一个非常强大的分布式配置文件。正确的理解和使用.htaccess文件&#xff0c;可以帮助我们优化自己的服务器或者虚拟主机。 如何启用htaccess 以windows为例&#xff0c;进入apache/conf目录&#xff0c;找到httpd.conf文件&a…

amaze ui各个模块简单说明

amaze ui各个模块简单说明 导航添加依据 http://amazeui.org/css/ 下面内容属学习笔记&#xff0c;如有理解偏差和错误请留言相告&#xff0c;感谢&#xff01;* &#xff08;官网这块写的很详细&#xff09; 一、基本样式 1.统一样式 说明了为什么使用Normalize&#xff0c;而…

由浅入深剖析.htaccess

1、.htaccess文件使用前提.htaccess的主要作用就是实现url改写&#xff0c;也就是当浏览器通过url访问到服务器某个文件夹时&#xff0c;作为主人&#xff0c;我们可以来接待这个url&#xff0c;具体地怎样接待它&#xff0c;就是此文件的作用。所有的访问都是通过URL实现&…

分享几个 Pyecharts 技巧,助你画出更直观/炫酷的图表

作者 | 俊欣来源 | 关于数据分析与可视化想必大家应该也已经看到很多关于数据分析的内容了&#xff0c;今天小编就为大家来分享一下国产可视化库pyecharts在绘制图表时一些的技巧&#xff0c;帮助读者画出更加酷炫以及可读性更高的图&#xff0c;当然在这之前呢&#xff0c;我们…

虚拟化--006 VCAC的sso配置成功

转载于:https://blog.51cto.com/williamliuwen/1686492

ionic app 开发和生产环境的配置

前言 像 Angular2 一样&#xff0c;希望 ionic 可以提供 2 个文件 ( environment.dev.ts 和 environment.prod.ts )&#xff0c;其中包含与开发和生产环境相对应的不同值的变量。在构建过程中&#xff0c;要在应用程序中绑定适当的文件。 实现步骤 在 src/config 中&#xff0c…

Android Properties 存储

1.初始化 1 private static void initProperties(){2 File logFile new File(Constants.PROGRESS_PROPERTIES);3 props new Properties();4 if(!logFile.exists()){5 //创建并初始化配置文件6 FileUtils.createFolder(Const…

php函数serialize()与unserialize()

php函数serialize()与unserialize()说明及案例。想要将已序列化的字符串变回 PHP 的值&#xff0c;可使用unserialize()。serialize()可处理除了resource之外的任何类型。甚至可以serialize()那些包含了指向其自身引用的数组。你正serialize()的数组&#xff0f;对象中的引用也…

2500 字全方面解读 Python 的格式化输出

作者 | 欣一来源 | Python爱好者集中营今天小编来和大家聊聊Python当中的格式化输出&#xff0c;希望会对大家所有帮助%占位符的使用我们先来看一下下面的这个例子&#xff0c;country_ "France" currency_ "Euro"print("%s is the currency of %s&…

python GUI编程( 二 ) (基于PyQt5)

第二节 本节介绍添加窗口图标&#xff0c;在窗口内添加按钮&#xff0c;在窗口内添加提示框。 导入模块&#xff1a; from PyQt5.QWidgets import QWidget,QPushButton,QApplication from PyQt5.QtGui import QIcon,QFont from PyQt5.QtCore import QCoreApplication import sy…

Linux+Apache2+openssl实现https验证

首先安装SSL&#xff0c;再编译安装APACHE&#xff0c;再配置证书即可 1.下载apache和openssl网址&#xff1a;http://www.apache.org http://www.openssl.org2.解压#tar zxvf httpd-2.0.54.tar.gz#tar zxvf openssl-0.9.7g.tar.gz3.编译安装openssl,这个软件主要是用来生…

践行科技向善,腾讯Light 把光引向厦门

作者 | 贾凯强出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;凛冬虽至&#xff0c;但沿着东南海域一路向南&#xff0c;总有寒风吹不灭的绿意&#xff0c;也有四季不败落的花香。今年的冬天厦门始终环绕着勃勃生机&#xff0c;也有无数的追光者来到了这里。因为关注…

【每天一点点】

>>>html 使用使用<a href"URL">ba bla bla</a>定义资源位置&#xff0c;使用<a href"#name"></a>跳转到name锚所在的位置&#xff1b;>>>eclipse的注释快捷键 方法一&#xff1a;使用Ctrl/快捷键&#xff0c;使…

模式的秘密-观察者模式(四)

区别对待观察者场景问题 两点需求&#xff1a; 第一&#xff1a;黄明女朋友只想接收下雨的天气预报。 第二&#xff1a;黄明老妈&#xff0c;想接收下雨或者下雪的天气预报。 解决思路&#xff1a; 情况之一&#xff1a; 如果天气晴天&#xff0c;按照黄明女朋友需要下雨添加&a…

PHP Webservice的发布与调用

PHP Webservice的发布与调用1. 环境配置 配置php.ini&#xff0c;把php_soap.dll前面的分号去掉&#xff0c;不然会报错 class soapserver not found重启apache后通过phpinfo()查看 这样是表示环境已经支持soap的webservice了&#xff0c;后面的事情就是写代码了。2. webserv…

全球首家!苹果市值达 3 万亿美元,创历史新高

作者 | 苏宓出品 | CSDN&#xff08;ID&#xff1a;CSDNnews&#xff09;成立于 1976 年的苹果公司&#xff0c;耗时 44 年&#xff0c;终于在 2018 年首次达到 1 万亿美元的市值。自此之后&#xff0c;苹果的发展仿佛安装了“高速马达”&#xff0c;短短两年后的 2020 年 8 月…