1. 一文讀懂零拷貝技術(shù)

        共 1526字,需瀏覽 4分鐘

         ·

        2021-04-06 16:21

        零拷貝技術(shù) 是編寫(xiě)高性能服務(wù)器的一個(gè)關(guān)鍵技術(shù),在介紹 零拷貝技術(shù) 前先說(shuō)明一下 用戶空間內(nèi)核空間。

        用戶空間

        通俗的說(shuō),用戶空間 就是運(yùn)行著用戶編寫(xiě)的應(yīng)用程序的虛擬內(nèi)存空間。在32位的操作系統(tǒng)中,每個(gè)進(jìn)程都有 4GB 獨(dú)立的虛擬內(nèi)存空間,而 0 ~ 3GB 的虛擬內(nèi)存空間就是用戶空間 。

        內(nèi)核空間

        內(nèi)核空間 就是運(yùn)行著操作系統(tǒng)代碼的虛擬內(nèi)存空間,而 3GB ~ 4GB 的虛擬內(nèi)存空間就是內(nèi)核空間。

        圖 1 展示了 用戶空間內(nèi)核空間 在進(jìn)程虛擬內(nèi)存空間所在的位置:

        發(fā)送文件

        為什么要介紹 用戶空間內(nèi)核空間 呢?

        我們先來(lái)回憶一下,服務(wù)端發(fā)送一個(gè)文件給客戶端一般需要進(jìn)行什么操作。一般來(lái)說(shuō),服務(wù)端發(fā)送一個(gè)文件給客戶端的步驟如下:

        • 首先需要調(diào)用 read 讀取文件的數(shù)據(jù)到用戶空間緩沖區(qū)中。

        • 然后再調(diào)用 write 把緩沖區(qū)的數(shù)據(jù)發(fā)送給客戶端 Socket。

          偽代碼如下:

        while ((n = read(file, buf, 4069)) > 0) {    write(sock, buf , n);}

        在上面的過(guò)程中,調(diào)用了 readwrite 兩個(gè)系統(tǒng)調(diào)用。read 系統(tǒng)調(diào)用是從文件中讀取數(shù)據(jù)到用戶空間的緩沖區(qū)中,所以調(diào)用 read 時(shí)需要從內(nèi)核空間復(fù)制數(shù)據(jù)到用戶空間,如圖 2 所示:

        圖2 就是數(shù)據(jù)的復(fù)制過(guò)程,首先會(huì)從文件中讀取數(shù)據(jù)到內(nèi)核的 頁(yè)緩存(page cache),然后再?gòu)捻?yè)緩存中復(fù)制到用戶空間的緩沖區(qū)中。

        而當(dāng)調(diào)用 write 系統(tǒng)調(diào)用把用戶空間緩沖區(qū)中的數(shù)據(jù)發(fā)送到客戶端 Socket 時(shí),首先會(huì)把緩沖區(qū)的數(shù)據(jù)復(fù)制到內(nèi)核的 Socket 緩沖區(qū)中,網(wǎng)卡驅(qū)動(dòng)會(huì)把 Socket 緩沖區(qū)的數(shù)據(jù)發(fā)送出去,如圖 3 所示:

        從上圖可以看出,服務(wù)端發(fā)送文件給客戶端的過(guò)程中需要進(jìn)行兩次數(shù)據(jù)復(fù)制,第一次是從內(nèi)核空間的頁(yè)緩存復(fù)制到用戶空間的緩沖區(qū),第二次是從用戶空間的緩沖區(qū)復(fù)制到內(nèi)核空間的 Socket 緩沖區(qū)。

        仔細(xì)觀察我們可以發(fā)現(xiàn),上圖中的頁(yè)緩存其實(shí)可以直接復(fù)制到 Socket 緩沖區(qū),而不需要復(fù)制到用戶空間緩沖區(qū)的。如圖 4 所示:

        如上圖所示,不需要用戶空間作為數(shù)據(jù)中轉(zhuǎn)的技術(shù)叫 零拷貝技術(shù)。那么,我們可以通過(guò)哪個(gè)系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)上圖中的技術(shù)呢?答案就是 sendfile,我們來(lái)看看 sendfile 系統(tǒng)調(diào)用的原型:

        #include <sys/sendfile.h>
        ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

        下面介紹一下 sendfile 各個(gè)參數(shù)的作用:

        • out_fd:數(shù)據(jù)接收方文件句柄(一般為 Socket 句柄)。

        • in_fd:數(shù)據(jù)提供方文件句柄(一般為文件句柄)。

        • offset:如果 offset 不為 NULL,表示從哪里開(kāi)始發(fā)送數(shù)據(jù)的偏移量。

        • count:表示需要發(fā)送多少字節(jié)的數(shù)據(jù)。

        sendfile 發(fā)送數(shù)據(jù)的過(guò)程如圖 5 所示:

        對(duì)比圖 5 與 圖 3,我們發(fā)現(xiàn)使用 sendfile 可以減少一次系統(tǒng)調(diào)用,并且減少一次數(shù)據(jù)拷貝過(guò)程。

        總結(jié)

        本文主要通過(guò) sendfile 系統(tǒng)調(diào)用來(lái)介紹 零拷貝技術(shù),但 零拷貝技術(shù) 不單只有 sendfile,如 mmap、splice直接I/O 等都是 零拷貝技術(shù) 的實(shí)現(xiàn),有興趣的可以參考 Linux 官方文檔或相關(guān)資料。



        瀏覽 46
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 成年视频在线 | 污污污污污污禁 网站 | 国产欧美日韩专区 | 97蜜桃 | 黄色日韩视频 |