apache、nginx和lighttpd等web服务具有sendfile相关配置,一些internet文档提到sendfile可以提高文件传输性能,那么sendfile到底是什么呢? 那个原理怎么样呢?
传统的文件传输(读/写方法)在实现上实际上很复杂,需要多次在上下文之间切换。 看看下面两行代码。
读取(file,tmp_buf,len );
write (套接字,tmp_buf,len );
上述两行代码是使用传统的读/写方法向套接字传输文件。
需要传输文件时,具体流程详细情况如下。
调用read函数并将文件数据复制到内核缓冲区
read函数返回,文件数据从内核缓冲区copy发送到用户缓冲区
write函数调用,用于将文件数据从用户缓冲区copy发送到内核套接字相关缓冲区。
数据从套接字缓冲区复制到相关协议引擎。
以上详细内容是基于以往的read/write方式的网络文件传送方式。 在这个过程中,可以看到文件数据实际上经过了4次复制操作。
硬盘-内核错误-用户错误-套接字相关缓冲区-协议引擎
另一方面,sendfile系统调用提供了一种减少多次拷贝并提高文件传输性能的方法。 Sendfile系统调用是在2.1版内核时引入的。
sendfile(socket,file,len );
执行过程如下:
sendfile系统调用,文件数据被复制到内核缓冲区
从内核缓冲区copy到内核中的套接字相关缓冲区
最后将套接字相关的缓冲区副本发送到协议引擎
与传统的读/写方法相比,2.1版内核引入的sendfile减少了内核缓冲区到用户缓冲区、user缓冲区到套接字相关缓冲区的文件复制,但内核版本2.4或更高版本的文件与2.1版的详细区别在于,当文件数据被复制到内核缓冲器时,仅将有关记录数据的位置和长度的数据存储在与套接字相关的缓存中,而不是将所有数据复制到与套接字相关的缓冲区中,并且实际数据是DMA