Linux内核sendfile分析

sendfile在Apache、nginx、lighttpd、web服务器上都有对应的设置项,究竟是sendfile是什么,它的原理是什么呢?

在传统的文件传输(读/写)中,真实情况相对比较复杂,需要经过多个上下文切换,以下两行代码是以传统的方式,将文件写入到socket。

read(file,tmp_buf,len);
write(socket,tmp_buf,len);

文件读写过程(传统方式)

1,调用read函数,将文件数据复制到内核缓冲区。

2,read函数从内核缓冲区返回文件数据,复制到用户缓冲区。

3,写函数的调用,文件数据从用户缓冲区复制到内核套接字相关的缓冲区。

4,数据从套接字缓冲区复制到协议引擎。

以上是传统方式通过网络传输文件的过程,在这个过程中,文件数据实际上经历了四次复制操作:

磁盘>内核缓冲区 - >用户缓冲区; >套接字协议引擎相关的缓冲区;>

sendfile操作过程

sendfile系统调用减少了复制,改善了文件传输的性能。Sendfile是在内核(kernel)2.1的版本中引入的。

sendfile(socket, file, len);

1,调用sendfile,数据文件复制到内核(kernel)缓冲区。

2,然后从内核缓冲区复制到socket相关的缓冲区。

3,最后,从套接字相关的缓冲区复制到协议引擎。

与传统的读/写方法相比,从之前内核缓冲区到用户缓冲区,用户缓冲区到套接字缓冲区,内核2.1中引入的sendfile减少了文件的复制过程,而在内核版本2.4中,Sendfile方法的实现更加简单,系统调用仍然是一样的。

Sendfile2.1与2.4的区别

与2.1版本的不同于之处在于细节,当文件数据被复制到内核缓冲区时,不再将所有数据复制到与socket相关的缓冲区,而是只记录与socket相关缓存的位置和长度有关的数据,数据会直接发送到DMA协议引擎模块,以减少复制操作,这种方式所支持的数据不能超过2G。