相比传统 Java 读取文件通过网卡发送过程中,省略了内核缓冲区 copy 到用户缓冲区的过程。

直接把数据在内核空间进行拷贝,减少了上下文切换(内核空间切换到用户空间)。

由内核缓冲区将数据拷贝到 Socket 缓冲区,然后通过网卡发送数据。

Transclude of zero_copy_sendfile.excalidraw

具体执行过程:

  • DMA copy 数据到内核缓冲区
  • cpu copy 数据到 socket 缓冲区
  • DMA 将 Socket 缓冲区数据 copy 到网卡发送

改进

由内核缓冲区直接拷贝到网卡发送,少了一次内核缓冲区 copy 到 Socket 缓冲区的过程。Socket 缓冲区只需要接受文件描述符数据和数据长度即可。

Transclude of zero_copy_sendfile_upgrade.excalidraw

具体执行过程:

  • DMA copy 数据到内核缓冲区
  • 文件描述符数据长度传给 Socket 缓冲区
  • DMA Gather copy 将数据 copy 到网卡发送

缺点

sendfile 的实现中,文件的数据都没有拷贝到用户空间,因此用户程序无法对读取的文件数据进行修改。

Java 中对应的实现

Java 中使用了 FileChannel.transferTo 的方法实现 sendFile。