linux内核系统调用--sendfile函数
在apache,nginx,lighttpd等webserver其中,都有一项sendfile相关的配置,在一些网上的资料都有谈到sendfile会提升文件传输性能,那sendfile究竟是什么呢?它的原理又是怎样呢?
在传统的文件传输里面(read/write方式),在实现上事实上是比較复杂的,须要经过多次上下文的切换,我们看一下例如以下两行代码:
- read(file, tmp_buf, len);
- write(socket, tmp_buf, len);
以上两行代码是传统的read/write方式进行文件到socket的传输。
当须要对一个文件进行传输的时候,其详细流程细节例如以下:
1、调用read函数,文件数据被copy到内核缓冲区
2、read函数返回,文件数据从内核缓冲区copy到用户缓冲区
3、write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。
4、数据从socket缓冲区copy到相关协议引擎。
一般来说一个网络应用是通过读硬盘数据,然后写数据到 socket 来完毕网络传输的。上面2行用代码解释了这一点,只是上面2行简单的代码掩盖了底层的非常多操作。来看看底层是怎么运行上面2行代码的:
1、系统调用 read() 产生一个上下文切换:从 user mode 切换到 kernel mode,然后 DMA 运行拷贝,把文件数据从硬盘读到一个 kernel buffer 里。
2、数据从 kernel buffer 复制到 user buffer,然后系统调用 read() 返回,这时又产生一个上下文切换:从kernel mode 切换到 user mode。
3、系统调用 write() 产生一个上下文切换:从 user mode 切换到 kernel mode,然后把步骤2读到 user buffer 的数据复制到 kernel buffer(数据第2次复制到 kernel buffer),只是这次是个不同的 kernel buffer,这个 buffer 和 socket 相关联。
4、系统调用 write() 返回,产生一个上下文切换:从 kernel mode 切换到 user mode(第4次切换了),然后 DMA 从 kernel buffer 拷贝数据到协议栈(第4次拷贝了)。
上面4个步骤有4次上下文切换,有4次拷贝,我们发现假设能降低切换次数和拷贝次数将会有效提升性能。在kernel 2.0+ 版本号中,系统调用 sendfile() 就是用来简化上面步骤提升性能的。sendfile() 不但能降低切换次数并且还能降低拷贝次数。
以上细节是传统read/write方式进行网络文件传输的方式,我们能够看到,在这个过程其中,文件数据实际上是经过了四次copy操作:
硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎
而sendfile系统调用则提供了一种降低以上多次copy,提升文件传输性能的方法。Sendfile系统调用是在2.1版本号内核时引进的:
- sendfile(socket, file, len);
执行流程例如以下:
1、sendfile系统调用,文件数据被copy至内核缓冲区
2、再从内核缓冲区copy至内核中socket相关的缓冲区
3、最后再socket相关的缓冲区copy到协议引擎
相较传统read/write方式,2.1版本号内核引进的sendfile已经降低了内核缓冲区到user缓冲区,再由user缓冲区到socket相关缓冲区的文件copy,而在内核版本号2.4之后,文件描写叙述符结果被改变,sendfile实现了更简单的方式,系统调用方式仍然一样,细节与2.1版本号的不同之处在于,当文件数据被拷贝到内核缓冲区时,不再将全部数据copy到socket相关的缓冲区,而是只将记录数据位置和长度相关的数据保存到socket相关的缓存,而实际数据将由DMA模块直接发送到协议引擎,再次降低了一次copy操作。
linux内核系统调用--sendfile函数的更多相关文章
- Linux内核-系统调用
Linux内核-系统调用 1.与内核通信 #系统调用在用户空间进程和硬件设备之间添加了一个中间层 作用:1.为用户空间提供了一种硬件的抽象接口 2.系统调用保证了系统的稳定和安全 3.出于每一个进程都 ...
- Linux内核的ioctl函数学习
Linux内核的ioctl函数学习 来源:Linux公社 作者:Linux 我这里说的ioctl函数是在驱动程序里的,因为我不知道还有没有别的场合用到了ioctl, 所以就规定了我们讨论的范围.为什 ...
- 举例跟踪linux内核系统调用
学号351+ 原创作品转载请注明出处 + 中科大孟宁老师的linux操作系统分析: https://github.com/mengning/linuxkernel/ 实验要求: 编译内核5.0 qem ...
- Linux内核中kzalloc函数详解
**************************************************************************************************** ...
- linux内核追踪——find_next_bit函数详详详解
写在前面 宗旨:把话说清楚,把道理讲透彻. 约定:所有代码均来自Linux内核2.6.24版. 建议:本文介绍得十分详细,但也略显繁琐,读者可以先看“Ⅴ.总结”部分带注释的源码,如果哪里不清楚,再回头 ...
- linux内核申请内存函数
kmap函数: 把某块高端内存映射到页表,然后返回给用户一个填好vitual字段的page结构 建立永久地址映射,不是简单的返回virtual字段的pageioremap: 驱动程序 ...
- Linux "零拷贝" sendfile函数中文说明及实际操作
Sendfile函数说明 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfile ...
- linux 内核态调试函数BUG_ON()[转]
一些内核调用可以用来方便标记bug,提供断言并输出信息.最常用的两个是BUG()和BUG_ON(). 当被调用的时候,它们会引发oops,导致栈的回溯和错误信息的打印.为什么这些声明会导致 oops跟 ...
- Linux "零拷贝" sendfile函数中文说明及实际操作分析
Sendfile函数说明 #include ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count); sendfile ...
随机推荐
- VS2012 创建项目失败,,提示为找到约束。。。。
首先查看 控制面板里已安装的更新 在Microsoft .NET Freamewofk 4.5 小 查看 是否有KB2833957和KB2840642这两个补丁(如下图) 如果有 卸载它 然后 下载 ...
- 【Eclipse】修改java代码不强制重启
找到tomcat的server.xml文件,修改以下代码,重新发布重启.然后修改java代码就可以不用重启了. 将reloadable=“true”改成reloadable="false&q ...
- myeclipse8.5如何注册,转自他出
Step: 1.建立一个任意名称的Java Project 2.在该工程中建立一个名文MyEclipseGen的Java文件(MyEclipseGen.java) 3.运行下面的代码,会在控制台出现& ...
- 【.Net基础拾遗】品味OO继承
0X1 引言 提起面向对象,每个人都有不同的见解.但提的最多的无非就是:对象.封装.继承.多态.差不多就是这些元素构成了面向对象设计开发的基本逻辑.面向对象编程,“对象”指的是什么?这里的" ...
- 使用zxing生成二维码 - servlet形式
因为项目有个功能需要打印二维码,因为我比较喜欢使用html+css+js实现,所以首先想到的是jquery.qrcode.js插件,这个插件可以用canvas和table生成二维码,效果也不错,不过对 ...
- A Magic Lamp(贪心+链表)
A Magic Lamp Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
- 用php 把数组中偶数,选择出来
我有这种一个小算法,把数组中的全部的偶数或技术分别选择出来.非常多人可能,会循环这个数组,而我恰恰不循环数组就能做到这一点.代码例如以下. function odd($var) { // return ...
- word2vec 中的数学原理具体解释(三)背景知识
word2vec 是 Google 于 2013 年开源推出的一个用于获取 word vector 的工具包,它简单.高效,因此引起了非常多人的关注.因为 word2vec 的作者 Tomas M ...
- 嵌入式MCU开发群资源
STM32CubeMX是一款图形化软件设置工具,允许使用图形化向导来生成C初始化代码.它是未来开发stm32系列产品的主流软件,是ST公司的主动原创,可以减轻开发工作,时间和费用.STM32Cube ...
- BZOJ 1047: [HAOI2007]理想的正方形( 单调队列 )
单调队列..先对每一行扫一次维护以每个点(x, y)为结尾的长度为n的最大最小值.然后再对每一列扫一次, 在之前的基础上维护(x, y)为结尾的长度为n的最大最小值. 时间复杂度O(ab) (话说还是 ...