sendfile函式 零拷貝

2021-07-24 06:48:02 字數 2867 閱讀 1060

零拷貝:零拷貝技術可以減少資料拷貝和共享匯流排操作的次數,消除通訊資料在儲存器之間不必要的中間拷貝過程,有效地提高通訊效率,是設計高速介面通道、實現高速伺服器和路由器的關鍵技術之一。

sendfile

#include 

ssize_t sendfile(int out_fd, int in_fd, off_t* offset, size_t count);

引數特別注意的是:in_fd必須是乙個支援mmap函式的檔案描述符,也就是說必須指向真實檔案,不能使socket描述符和管道。

out_fd必須是乙個socket描述符.

由此可見sendfile幾乎是專門為在網路上傳輸檔案而設計的。

out_fd:已經開啟了,用於寫操作的檔案描述符

in_fd:已經開啟了,用於讀操作的檔案描述符

offset:偏移量:表示sendfile函式從in_fd中的哪一偏移量開始讀取資料,如果是0表示從檔案的開始讀,否則從相應的偏移量讀取,如果是迴圈讀取的時候,下一次offset值應為sendfile函式返回值加上本次的offset的值。

count:是在兩個描述符之間拷貝的位元組數

返回值:

如果成功的拷貝,返回寫操作到out_fd的位元組數,錯誤返回-1,並相應的設定error資訊。

關於sendfile與read和write的比較

伺服器響應乙個http請求的步驟如下:

1.把磁碟檔案讀入核心緩衝區

2.從核心緩衝區讀到記憶體

3.處理(靜態資源不需要處理)

4.傳送到網絡卡的核心緩衝區(傳送快取)

5.網絡卡傳送資料

而sendfile系統呼叫,省略了2,3步,磁碟檔案被直接傳送到了網絡卡的記憶體緩衝區,減少了資料複製和核心態切換的開銷。

sendfile一直都在核心態進行

普通的read和write的傳統網路傳輸過程的步驟

read(file, tmp_buf, len);

write(socket, tmp_buf, len);

硬碟 >> kernel buffer >> user buffer >> kernel socket buffer >> 協議棧

一般的網路應用是通過讀硬碟資料,然後寫資料到socket來完成網路傳輸的。

底層實現如下:

1.系統呼叫read()產生乙個上下文切換:從使用者模式切換到核心模式,然後dma(直接記憶體訪問)執行拷貝,把檔案資料從硬碟讀到乙個核心緩衝區裡面去。

2.資料從核心緩衝區拷貝到使用者態緩衝區,然後系統呼叫read()返回,這時又產生乙個上下文切換:從核心狀態切換到使用者態。

3.系統呼叫write()產生乙個上下文切換:從使用者態切換到核心態,然後把步驟2中讀到使用者緩衝區的資料拷貝到核心態緩衝區(資料第二次拷貝到核心態緩衝區),不過這次是個不同的核心態緩衝區,這個緩衝區和socket相關聯。

4.系統呼叫write()返回,產生乙個上下文切換:從核心態切換到使用者態(第4次切換),然後dma從核心緩衝區拷貝資料到協議棧(第四次拷貝)。

上述4個步驟,4次上下文切換,4次拷貝,我們發現減少他的切換和拷貝次數,將有效提高效能。這也是sendfile提高效能的方法。

關於sendfile進行網路傳輸的過程

sendfile(socket, file, len);

硬碟 >> kernel buffer (快速拷貝到kernel socket buffer) >> 協議棧

1.系統呼叫sendfile()通過dma把硬碟資料拷貝到核心緩衝區,然後資料直接拷貝到另乙個與socket相關的核心緩衝區。(區別)這裡沒有使用者態和核心態之間的切換,在核心態中直接完成了從乙個緩衝區到另乙個緩衝區的拷貝。

2.dma把資料從核心緩衝區直接拷貝給協議棧,沒有切換,也不需要資料從使用者態拷貝到核心態,因為資料就在核心裡面。

由此比較,sendfile遠比read和write方式在進行資料拷貝時高效。

關於sendfile的應用**–**作用是把a檔案(和客戶端程式在同一目錄下)傳遞給伺服器端

服務端

#include 

#include

#include

#include

#include

#include

#include

#include

int main(int argc,char* argv)

char buff[128] = ;

recv(c,buff,127,0);

printf("%s",buff);

}close(c);

return

0;}

客戶端

#include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

int main(int argc,char* argv)

printf("發出了%d個位元組\n",len);

}close(sockfd);

return

0;}

sendfile 實現零拷貝詳解

2013年11月18日 11 17 供稿中心 網際網路運營部 摘要 linux的sendfile 系統呼叫 伺服器響應乙個http請求的步驟如下 1 把磁碟檔案讀入核心緩衝區 2 從核心緩衝區讀到記憶體 3 處理 靜態資源不需處理 4 傳送到網絡卡的核心緩衝區 傳送快取 5 網絡卡傳送資料 資料從第...

sendfile「零拷貝」和mmap記憶體對映

在學習sendfille之前,我們先來了解一下瀏覽器訪問頁面時,後台伺服器的大致工作流程。下圖是從使用者訪問某個頁面到頁面的顯示這幾秒鐘的時間當中,在後台的整個工作過程。如上圖,黑色箭頭所示的過程,是傳統方式的資料傳輸 第一步 當使用者請求www.test.com index.html網頁時,ngi...

sendfile「零拷貝」和mmap記憶體對映

在學習sendfille之前,我們先來了解一下瀏覽器訪問頁面時,後台伺服器的大致工作流程。下圖是從使用者訪問某個頁面到頁面的顯示這幾秒鐘的時間當中,在後台的整個工作過程。如上圖,黑色箭頭所示的過程,是傳統方式的資料傳輸 第一步 當使用者請求www.test.com index.html網頁時,ngi...