电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 1803 人浏览分享

linux高级I/O函数sendfile

[复制链接]
1803 0
本帖最后由 luowei 于 2017-7-19 18:16 编辑


sendfile函数,顾名思义,用于传输文件而设计的函数。是Linux下的系统调用函数。

函数原型:

  1. #include<sys/sendfile.h>
  2. ssize_t sendfile(int out_fd,int in_fd,off_t* offset,size_t count);
复制代码

sendfile函数在两个文件描述符之间直接传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,效率很高,这被称为零拷贝。

函数参数:


  • out_fd参数是代写入内容的文件描述符。
  • in_fd参数是待读出内容的文件描述符。
  • offset参数指定从读入文件流的哪个位置开始读,如果为空,则使用读入文件流默认的起始位置。
  • count参数指定在文件描述符in_fd和out_fd之间传输的字节数。

几点说明:

in_fd必须是一个支持类似mmap函数的文件描述符,即它必须指向真实文件,不能是socket和管道。

在Linux2.6.33之前,out_fd必须是一个socket,而从Linux2.6.33之后,out_fd可以是任何文件。这意味着我们不仅可以用该函数在网络上传输文件,还可以使用该函数对本地的文件实现拷贝操作。

返回值:

sendfile成功时返回传输的字节数,失败则返回-1并设置errno。

与read和write系统调用函数的比较:

我们称sendfile函数为零拷贝函数,效率很高。那效率高到底体现在哪里了呢?

比如说客户端想把本地的一个文件通过socket发送给服务器,我们分析一下使用read&write和使用sendfile函数实现的差别:

如果我们使用read和write函数,需要进行如下几个步骤:

1. 调用read函数,文件数据被copy到内核缓冲区

2. read函数返回,文件数据从内核缓冲区copy到用户缓冲区


3. write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。


4. 数据从socket缓冲区copy到相关协议引擎。

以上细节是传统read/write方式进行网络文件传输的方式,我们可以看到,在这个过程当中,文件数据实际上是经过了四次copy操作:

硬盘—>内核buf—>用户buf—>socket相关缓冲区—>协议引擎

而使用sendfile函数,需要进行如下几个步骤:


1. sendfile系统调用,文件数据被copy至内核缓冲区


2. 再从内核缓冲区copy至内核中socket相关的缓冲区


3. 最后再socket相关的缓冲区copy到协议引擎

对比我们可以得出,相比使用sendfile函数,Read & Write方式带来的性能损耗主要有两点:

1. 不必要的内存拷贝。即多了一次从内核缓冲区到用户缓冲区的数据拷贝。


2. 系统调用带来的额外的用户态/内核态上下文切换。我们知道,使用系统调用会发生从内核态到用户态之间的相互转换。使用read&write方式,多使用了一次系统调用,就多了一次上下文切换,降低了性能。

综上我们可以得出,sendfile函数不但能减少切换次数而且还能减少拷贝次数,是一个非常高效的数据拷贝函数,尤其在传输一个非常大的文件时,sendfile函数的高性能体现的更为明显。因此,在以后我们设计到网络传输文件时,应该使用sendfile函数,提高效率。




您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

关注

0

粉丝

60

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.