原文: https://blog.csdn.net/lk_wkqd/article/details/50242523
對于網絡數據傳輸或I/O數據拷貝而言,零拷貝技術主要指的是避免內核緩沖區和用戶緩沖區中的不必要的數據拷貝操作。
Linux傳統I/O
Linux傳統I/O操作是一種緩沖I/O,在數據傳輸中,操作系統會將 I/O 的數據緩存在文件系統的頁緩存中,即操作系統內核緩沖區中。
比如:在網絡中傳輸一個文件時,發送端應用程序會先檢查內核緩沖區中有沒有需要發送的這個文件的數據,如果沒有,則會將這個文件從磁盤拷貝到內核緩沖區中,然后再從內核緩沖區拷貝到應用程序的用戶緩沖區,如果應用程序不對數據進行處理或處理完畢之后,再將文件拷貝到內核中的socket發送緩沖區(比如TCP發送緩沖區),待內核socket緩沖區中有足夠的數據時,就會把數據發送到網卡上,然后在網絡上進行傳輸。其數據傳輸過程如下圖所示:
其過程至少發生了四次數據的拷貝,其頻繁的讀寫對CPU的使用和內存的帶寬開銷是非常大的。
零拷貝技術
零拷貝技術相對傳統I/O技術來說,主要是避免數據傳輸過程中頻繁的數據拷貝操作,提高傳輸效率,并且使CPU有更多時間執行其它任務。
零拷貝技術分類
- 直接I/O機制:
通過上面的介紹,普通I/O(即緩沖I/O)會被內核緩存。相對于普通I/O機制,直接I/O機制對文件的訪問不經過內核的緩存,數據直接在磁盤和應用程序地址空間進行傳輸。這就避免了內核緩沖區和用戶緩沖區的數據拷貝,降低了讀寫操作對CPU的使用以及對內存帶寬的占用。
但是直接 I/O 不能提供緩存 I/O 的優勢。緩存 I/O 的讀操作可以從高速緩沖存儲器中快速獲取數據,而直接 I/O 的讀數據操作會造成磁盤的同步讀,導致進程需要較長的時間才能執行完。
- 不經過用戶緩沖區:
主要是指不需要將數據拷貝或者映射到應用程序地址空間中,直接在內核中傳輸。
比如sendfile( )系統調用:sendfile( ) 系統調用利用 DMA 將文件中的數據拷貝到操作系統內核緩沖區中,然后數據被拷貝到與 socket 相關的內核緩沖區中。接下來,DMA 將數據從內核 socket 緩沖區中拷貝到網卡中去。如果在用戶調用 sendfile ( ) 系統調用進行數據傳輸的過程中有其他進程截斷了該文件,那么 sendfile ( ) 系統調用會簡單地返回給用戶應用程序中斷前所傳輸的字節數,errno 會被設置為 success。
其傳輸過程如下:
由于sendfile( )函數只能往socket上寫數據,因此它幾乎是專門為了在網絡上傳輸文件而設計的。
DMA簡介:Direct Memory Access(存儲器直接訪問)。這是指一種高速的數據傳輸操作,允許在外部設備和存儲器之間直接讀寫數據,既不通過CPU,也不需要CPU干預。整個數據傳輸操作在一個稱為”DMA控制器”的控制下進行的。CPU除了在數據傳輸開始和結束時做一點處理外,在傳輸過程中CPU可以進行其他的工作。這樣,在大部分時間里,CPU和輸入輸出都處于并行操作。因此,使整個計算機系統的效率大大提高。
- 優化數據在內核緩沖區和用戶緩沖區之間的傳輸:
保留了傳統的在用戶應用程序地址空間和操作系統內核地址空間之間傳遞數據的技術,但卻在傳輸上進行優化。
比如寫時復制技術:如果多個應用程序同時訪問同一塊數據,但這塊數據只有一份,那么可以為這些應用程序分配指向這塊數據的指針,在每一個應用程序看來,它們都擁有這塊數據的一份數據拷貝。若一個應用程序需要訪問但不修改該數據時,直接讀這個數據而不復制,但當應用程序需要對這塊數據進行修改的時候,就需要將數據真正地拷貝到該應用程序的地址空間中去,也就是說,該應用程序擁有了一份真正的私有數據拷貝,對這份私有數據進行修改。這樣做是為了避免該應用程序對這塊數據做的更改被其他應用程序看到。這個過程對于應用程序來說是透明的,如果應用程序永遠不會對所訪問的這塊數據進行任何更改,那么就永遠不需要將數據拷貝到應用程序自己的地址空間中去。
以上只進行了比較淺的分析,知識有限,找了一些深入的資料沒有看懂,比如其實現機理,等需要對Linux內核深入學習的時候在回頭看,不過暫時理解這些對于網絡編程已經有很大的幫助了。