Linux-零拷貝(Zero Copy)

理論是灰色的,實踐之樹長青🌲 ——恩格斯

概要

一般當用戶需要把數據發送至網絡的時候,有三種方式可以實現:

  • 直接I/O
  • 內存映射文件
  • 零拷貝(Zero Copy)

零拷貝(Zero Copy)是提升IO效率的一大利器,一般爲了讓傳輸效率更高一些會採用零拷貝的方式來提升效率!

直接I/O

僞代碼如下:

fd1 = 打開的文件描述符
fd2 = 打開的socket描述符
buffer = 應用程序內存
read(fd1, buffer...//先把數據從文件中讀出來
write(fd2, buffer...)  //再通過網絡發送出去

根據直接IO的數據傳輸方式,可以得出如下示意圖:
在這裏插入圖片描述
整個過程會有四次數據拷貝,讀進來兩次寫回去又兩次。
磁盤 - > 內核緩衝區 -> 應用程序內存 -> Socket緩衝區 -> 網絡

內存映射文件

僞代碼如下:

fd1 = 文件描述符
fd2 = 打開的socket描述符
buffer = 應用程序內存
mmap(fd1, buffer...)  //將磁盤數據映射到buffer
write(fd2, buffer...)  //通過網絡發送出去

根據內存映射文件的數據傳輸方式,可以得出如下示意圖:
在這裏插入圖片描述
整個過程會有三次數據拷貝,不再經過應用程序內存,直接在內核中將內存緩衝區數據拷貝至Socket緩衝區。

⚠️注意:這裏分清楚拷貝和映射的區別。
拷貝:把數據從一塊空間複製到另一塊空間;
映射:相當於只是持有該數據區域的一個引用(地址),數據本身只有一份;

零拷貝

如果使用零拷貝,則內核緩衝區到Socket緩衝區的數據拷貝也省略了。

在零拷貝中,內核緩衝區和Socket緩衝區之間並沒有做數據拷貝,只是一個地址映射,底層的網卡驅動程序要讀取數據併發送到網絡時,看似讀取的是Socket緩衝區的數據,實際上讀取的是 內核緩衝區的數據。
在這裏插入圖片描述
在這裏,我們看到雖然叫零拷貝,實際是2次數據拷貝,1次是從磁 盤到內核緩衝區,1次是從內核緩衝區到網絡。之所以叫零拷貝,是從 內存的角度來看的,數據在內存中沒有發生過數據拷貝,只在內存和 I/O之間傳輸。

在Linux系統中,零拷貝的系統API爲:

sendfile(int out_fd, int in_fd, off_t *offset, size_t count)
// out_fd: socket描述符
// in_fd: 文件描述符

總結

對於把文件數據發送到網絡的這個場景,分析數據拷貝和內存拷貝的次數。

數據拷貝 內存拷貝
直接IO 4次 2次
內存映射文件 3次 1次
零拷貝 2次 0次
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章