sendfile学习

Posted 笨鸟居士的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了sendfile学习相关的知识,希望对你有一定的参考价值。

参考

https://zhuanlan.zhihu.com/p/20768200?refer=auxten

 

而成本很多时候的体现就是对计算资源的消耗,其中最重要的一个资源就是CPU资源。

 

Sendfile(2)在这个时代背景下于2003年前后被加入Linux Kernel,陆续在各大UNIX、Linux、Solaris平台上获得了支持。这个系统内核调用本身被设计出来是用来从磁盘到TCP协议栈拷贝数据用的,但也我们也是可以把它用来做两个文件之间的数据拷贝。

在Linux Kernel 2.6版本中,这个系统调用的原型是这样的:

ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
  • in_fd 被打开是等待读数据的fd.
  • out_fd 被打开是等待写数据的fd.
  • Offset 是在正式开始读取数据之前应该向前偏移的byte数.
  • count 是需要在两个fd之间“搬移”的数据的byte数.

参数特别注意的是:in_fd必须是一个支持mmap函数的文件描述符,也就是说必须指向真实文件,不能使socket描述符和管道。

out_fd必须是一个socket描述符。

由此可见sendfile几乎是专门为在网络上传输文件而设计的。


在sendfile(2)出现之前,我们想要把一个文件发送到socket上需要进行如下几个步骤:

  1. 调用read(2)函数,文件数据被copy到内核缓冲区
  2. read(2)函数返回,文件数据从内核缓冲区copy到用户缓冲区
  3. write(2)函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区。
  4. 数据从socket缓冲区copy到相关协议引擎。

 

 

相比sendfile(2),“Read & Write”方式带来的性能损耗主要有两点:

  1. 不必要的内存拷贝。
  2. 系统调用带来的额外的用户态/内核态上下文切换(Context Switch)。

 

 

而我们知道,上下文切换涉及到非常多的CPU、内存堆栈的操作,会让分支预测失败率大增,所以频繁的上线文切换是高性能编程的大忌。类UNIX操作系统里都有一个系统命令vmstat可以展示当前系统的“Context Switch”的量(--system--下的cs列):

 

 

以上是关于sendfile学习的主要内容,如果未能解决你的问题,请参考以下文章

零拷贝

Express res.sendFile 没有上传 CSS

下载中带有文件名的NodeJS sendFile

Angularjs - TypeError:路径必须是绝对路径或指定根到 res.sendFile

IOS开发-OC学习-常用功能代码片段整理

java SpringRetry学习的代码片段