一文讀懂零拷貝技術
零拷貝技術
是編寫高性能服務器的一個關鍵技術,在介紹 零拷貝技術
前先說明一下 用戶空間
與 內核空間
。
用戶空間
通俗的說,用戶空間
就是運行着用戶編寫的應用程序的虛擬內存空間。在 32 位的操作系統中,每個進程都有 4GB 獨立的虛擬內存空間,而 0 ~ 3GB 的虛擬內存空間就是用戶空間 。
內核空間
內核空間
就是運行着操作系統代碼的虛擬內存空間,而 3GB ~ 4GB 的虛擬內存空間就是內核空間。
圖 1 展示了 用戶空間
與 內核空間
在進程虛擬內存空間所在的位置:
發送文件
爲什麼要介紹 用戶空間
和 內核空間
呢?
我們先來回憶一下,服務端發送一個文件給客戶端一般需要進行什麼操作。一般來說,服務端發送一個文件給客戶端的步驟如下:
-
首先需要調用
read
讀取文件的數據到用戶空間緩衝區中。 -
然後再調用
write
把緩衝區的數據發送給客戶端 Socket。僞代碼如下:
while ((n = read(file, buf, 4069)) > 0) {
write(sock, buf , n);
}
在上面的過程中,調用了 read
和 write
兩個系統調用。read
系統調用是從文件中讀取數據到用戶空間的緩衝區中,所以調用 read
時需要從內核空間複製數據到用戶空間,如圖 2 所示:
圖 2 就是數據的複製過程,首先會從文件中讀取數據到內核的 頁緩存(page cache)
,然後再從頁緩存中複製到用戶空間的緩衝區中。
而當調用 write
系統調用把用戶空間緩衝區中的數據發送到客戶端 Socket 時,首先會把緩衝區的數據複製到內核的 Socket 緩衝區中,網卡驅動會把 Socket 緩衝區的數據發送出去,如圖 3 所示:
從上圖可以看出,服務端發送文件給客戶端的過程中需要進行兩次數據複製,第一次是從內核空間的頁緩存複製到用戶空間的緩衝區,第二次是從用戶空間的緩衝區複製到內核空間的 Socket 緩衝區。
仔細觀察我們可以發現,上圖中的頁緩存其實可以直接複製到 Socket 緩衝區,而不需要複製到用戶空間緩衝區的。如圖 4 所示:
如上圖所示,不需要用戶空間作爲數據中轉的技術叫 零拷貝技術
。那麼,我們可以通過哪個系統調用來實現上圖中的技術呢?答案就是 sendfile
,我們來看看 sendfile
系統調用的原型:
#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
下面介紹一下 sendfile
各個參數的作用:
-
out_fd
:數據接收方文件句柄(一般爲 Socket 句柄)。 -
in_fd
:數據提供方文件句柄(一般爲文件句柄)。 -
offset
:如果 offset 不爲 NULL,表示從哪裏開始發送數據的偏移量。 -
count
:表示需要發送多少字節的數據。
sendfile
發送數據的過程如圖 5 所示:
對比圖 5 與 圖 3,我們發現使用 sendfile
可以減少一次系統調用,並且減少一次數據拷貝過程。
總結
本文主要通過 sendfile
系統調用來介紹 零拷貝技術
,但 零拷貝技術
不單隻有 sendfile
,如 mmap
、splice
和 直接I/O
等都是 零拷貝技術
的實現,有興趣的可以參考 Linux 官方文檔或相關資料。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/MKb80nS8JvrDO2287JBnQg