Fork me on GitHub

Sendfile机制

得到一个index.html页面,

个人理解 :首先进入网卡--从网卡的缓冲区复制到内核的缓冲区(socket  buffer)--通过内核缓冲区在复制到应用程序(如Apache)--httpd收到请求,得到要访问index.html页面,而index.html的页面在磁盘上,应用程序httpd是没有能力访问的磁盘的,--应用程序发起请求给内核,通过内核访问磁盘上的文件--内核去磁盘上找文件--内核把磁盘上的文件读取到内核缓冲区中--内核将缓冲区中的文件复制给httpd--httpd拿到之后,在里面分装头部--封装完成后发到内核缓冲区--内核缓冲区在交给网卡---网卡在回复给用户

 

官方讲解:

硬盘 >> kernel buffer >> user buffer >> kernel socket buffer >> 协议栈
  一般网络应用通过读硬盘数据,写数据到 socket 来完成网络传输,底层执行过程:
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() 不但能减少切换次数而且还能减少拷贝次数
  用 sendfile() 来进行网络传输的过程:
sendfile(socket, file, len);
硬盘 >> kernel buffer (快速拷贝到kernel socket buffer) >> 协议栈
1 系统调用 sendfile() 通过 DMA 把硬盘数据拷贝到 kernel buffer,然后数据被 kernel 直接拷贝到另外一个与 socket 相关的 kernel buffer。这里没有 user mode 和 kernel mode 之间的切换,在 kernel 中直接完成了从一个 buffer 到另一个 buffer 的拷贝
2 DMA 把数据从 kernel buffer 直接拷贝给协议栈,没有切换,也不需要数据从 user mode 拷贝到 kernel mode,因为数据就在 kernel 里

sendfile 当从磁盘空间上找到文件之后,直接封装个头部,直接发给网卡,通过网卡发给用户

Apache默认开启这个功能,禁用的话,就Sendfile off 这个技术还有个称呼叫零复制

nginx也有这个技术

posted @ 2021-03-26 19:57  Alex-Lzy  阅读(290)  评论(0编辑  收藏  举报