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