零拷貝技術(shù)研究與實(shí)現(xiàn)_第1頁
零拷貝技術(shù)研究與實(shí)現(xiàn)_第2頁
零拷貝技術(shù)研究與實(shí)現(xiàn)_第3頁
零拷貝技術(shù)研究與實(shí)現(xiàn)_第4頁
零拷貝技術(shù)研究與實(shí)現(xiàn)_第5頁
已閱讀5頁,還剩10頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、零拷貝技術(shù)研究與實(shí)現(xiàn)2007-09-12 13:52作者:梁健(firstdot)E-MAIL: firstdot感謝王超、史曉龍的共同研究與大力幫助一基本概念零拷貝(zero-copy)基本思想是:數(shù)據(jù)報(bào)從網(wǎng)絡(luò)設(shè)備到用戶程序空間傳遞的過程中,減少數(shù)統(tǒng)調(diào)用,實(shí)現(xiàn)CPU 的零參與,徹底消除CPU 在這方面的負(fù)載。實(shí)現(xiàn)零拷貝用到的最主要技術(shù)和內(nèi)存區(qū)域映射技術(shù)。如圖1 所示,傳統(tǒng)的網(wǎng)絡(luò)數(shù)據(jù)報(bào)處理,需要經(jīng)過網(wǎng)絡(luò)設(shè)備到操作系空間到用戶應(yīng)用程序空間這兩次拷貝,同時(shí)還需要經(jīng)歷用戶向系統(tǒng)發(fā)出的系統(tǒng)調(diào)用。而零拷貝技術(shù)將網(wǎng)絡(luò)數(shù)據(jù)報(bào)直接傳遞到系統(tǒng)內(nèi)核預(yù)先分配的地址空間中,避免CPU 的參與;同時(shí),將報(bào)的內(nèi)存區(qū)域映射

2、到檢測程序的應(yīng)用程序空間(還有一種方式是在用戶空間建立一緩存,并類似于 linux 系統(tǒng)下的kiobuf 技術(shù)),檢測程序直接對這塊內(nèi)存進(jìn)行訪問,從而減少了系統(tǒng)內(nèi)拷貝,同時(shí)減少了系統(tǒng)調(diào)用的開銷,實(shí)現(xiàn)了真正的“零拷貝 ”。圖 1 傳統(tǒng)數(shù)據(jù)處理與零拷貝技術(shù)之比較二實(shí)現(xiàn)在 redhat7.3 上通過修改其內(nèi)核源碼中附帶的8139too.c 完成零拷貝的試驗(yàn),主要想法是:在塊啟動(dòng)時(shí)申請一內(nèi)核緩存,并建立一數(shù)據(jù)結(jié)構(gòu)對其進(jìn)行管理,然后試驗(yàn)性的向該緩存寫入多過 proc 文件系統(tǒng)將該緩存的地址傳給用戶進(jìn)程;用戶進(jìn)程通過讀proc 文件系統(tǒng)取得緩存地映射,從而可以從其中讀取數(shù)據(jù)。哈哈,為了偷懶,本文只是對零拷

3、貝思想中的地址映射部分現(xiàn) DMA 數(shù)據(jù)傳輸 (太麻煩了, 還得了解硬件), 本試驗(yàn)并不是一個(gè)IDS 產(chǎn)品中抓包模塊的一中實(shí)現(xiàn)零拷貝,除了DMA 外,還有一些問題需考慮,詳見本文第三節(jié)的分析。以下為實(shí)現(xiàn)細(xì)代碼見附錄。步驟一:修改網(wǎng)卡驅(qū)動(dòng)程序a.在網(wǎng)卡驅(qū)動(dòng)程序中申請一塊緩存:由于在 linux2.4.X內(nèi)核中支持的最大可分配連續(xù)緩存大要存儲(chǔ)更大量的網(wǎng)絡(luò)數(shù)據(jù)報(bào)文,則需要分配多塊非連續(xù)的緩存,并使用鏈表、數(shù)組或 hash 表來#define PAGES_ORDER 9unsigned long su1_2su1_2 = _get_free_pages(GFP_KERNEL,PAGES_ORDER);b

4、. 向緩存中寫入數(shù)據(jù):真正IDS 產(chǎn)品中的零拷貝實(shí)現(xiàn)應(yīng)該是使用DMA 數(shù)據(jù)傳輸把網(wǎng)卡硬件緩存。作為試驗(yàn),我只是向該緩存中寫入幾個(gè)任意的字符串,如果不考慮DMA 而又想向緩據(jù)包,可以在8139too.c 的 rtl8139_rx_interrupt() 中調(diào)用 netif_rx() 后插入以下代碼:/put_pkt2mem_n+; / 包個(gè)數(shù)/put_mem(skb->data,pkt_size);其中 put_pkt2mem_n 變量和 put_mem 函數(shù)見附錄。c. 把該緩存的物理地址傳到用戶空間:由于在內(nèi)核中申請的緩存地址為虛擬地址,而在用戶存的物理地址,所以首先要進(jìn)行虛擬地址到物

5、理地址的轉(zhuǎn)換,在linux系統(tǒng)中可以使用內(nèi)核虛對應(yīng)的物理地址。把緩存的地址傳到用戶空間需要在內(nèi)核與用戶空間進(jìn)行少量數(shù)據(jù)傳輸,這可文件系統(tǒng)等方式實(shí)現(xiàn),在這里采用了proc 文件系統(tǒng)方式。int read_procaddr(char *buf,char *start,off_t offset,int count,int *eof,void *data)sprintf(buf,"%un",_pa(su1_2);*eof = 1;return 9;create_proc_read_entry("nf_addr",0,NULL,read_procaddr,NULL

6、);步驟二:在用戶程序中實(shí)現(xiàn)對共享緩存的訪問a.讀取緩存地址:通過直接讀取 proc文件的方式便可獲得。char addr9;int fd_procaddr;unsigned long ADDR;fd_procaddr = open("/proc/nf_addr",O_RDONLY);read(fd_procaddr,addr,9);ADDR = atol(addr);b.把緩存映射到用戶進(jìn)程空間中:在用戶進(jìn)程中打開 /dev/mem設(shè)備(相當(dāng)于物理內(nèi)存),使用序申請的緩存映射到自己的進(jìn)程空間,然后就可以從中讀取所需要的網(wǎng)絡(luò)數(shù)據(jù)包了。char *su1_2;int fd;f

7、d=open("/dev/mem",O_RDWR);su1_2 = mmap(0,PAGES*4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, ADDR三分析零拷貝中存在的最關(guān)鍵問題是同步問題,一邊是處于內(nèi)核空間的網(wǎng)卡驅(qū)動(dòng)向緩存中寫入網(wǎng)進(jìn)程直接對緩存中的數(shù)據(jù)包進(jìn)行分析(注意,不是拷貝后再分析),由于兩者處于不同的空得更加復(fù)雜。緩存被分成多個(gè)小塊,每一塊存儲(chǔ)一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包并用一數(shù)據(jù)結(jié)構(gòu)表示,本試驗(yàn)標(biāo)志位來標(biāo)識什么時(shí)候可以進(jìn)行讀或?qū)懀?dāng)網(wǎng)卡驅(qū)動(dòng)向包數(shù)據(jù)結(jié)構(gòu)中填入真實(shí)的包數(shù)據(jù)后便標(biāo)戶進(jìn)程對包數(shù)據(jù)結(jié)構(gòu)中的數(shù)據(jù)分析完后便標(biāo)識該包為可寫,這基本

8、解決了同步問題。然而, 由要直接對緩存中的數(shù)據(jù)進(jìn)行入侵分析,而不是將數(shù)據(jù)拷貝到用戶空間后再進(jìn)行分析,這使得有可能造成網(wǎng)卡驅(qū)動(dòng)無緩存空間可以寫,從而造成一定的丟包現(xiàn)象,解決這一問題的關(guān)鍵在于小的緩存容易造成丟包,太大的緩存則管理麻煩并且對系統(tǒng)性能會(huì)有比較大的影響。四附錄a. 8139too.c 中加入的代碼/*add_by_liangjian for zero_copy*/#include <linux/wrapper.h>#include <asm/page.h>#include <linux/slab.h>#include <linux/proc_f

9、s.h>#define PAGES_ORDER 9#define PAGES 512#define MEM_WIDTH 1500/*added*/*add_by_liangjian for zero_copy*/struct MEM_DATA/int key;unsigned short width;/* 緩沖區(qū)寬度*/unsigned short length;/* 緩沖區(qū)長度*/unsigned short wtimes;/* 寫進(jìn)程記數(shù),預(yù)留,為以后可以多個(gè)進(jìn)程寫*/unsigned short rtimes;/* 讀進(jìn)程記數(shù),預(yù)留,為以后可以多個(gè)進(jìn)程讀*/unsigned sho

10、rt wi;/* 寫指針 */unsigned short ri;/* 讀指針 */ * mem_data;struct MEM_PACKETunsigned int len;unsigned char packetpMEM_WIDTH - 4;/*sizeof(unsigned int) = 4*/;unsigned long su1_2;/* 緩存地址*/*added*/*add_by_liangjian for zero_copy*/刪除緩存void del_mem()int pages = 0;char *addr;addr = (char *)su1_2;while (pages &

11、lt;=PAGES -1)mem_map_unreserve(virt_to_page(addr);addr = addr + PAGE_SIZE;pages+;free_pages(su1_2,PAGES_ORDER);void init_mem() /*初始化緩存輸入 : aMode: 緩沖區(qū)讀寫模式: r,w返回 : 00: 失敗*>0: 緩沖區(qū)地址*int i;int pages = 0;char *addr;char *buf;struct MEM_PACKET * curr_pack;su1_2 = _get_free_pages(GFP_KERNEL,PAGES_ORDER

12、); printk("%xn",su1_2);addr = (char *)su1_2;while (pages <= PAGES -1)mem_map_reserve(virt_to_page(addr);/ 需使緩存的頁面常駐內(nèi)存addr = addr + PAGE_SIZE;pages+;mem_data = (struct MEM_DATA *)su1_2;mem_data0.ri = 1;mem_data0.wi = 1;mem_data0.length = PAGES*4*1024 / MEM_WIDTH;mem_data0.width = MEM_WID

13、TH;/* initial su1_2 */for(i=1;i<=mem_data0.length;i+)buf = (void *)(char *)su1_2 + MEM_WIDTH * i); curr_pack = (struct MEM_PACKET *)buf;curr_pack->len = 0; int put_mem(char *aBuf,unsigned int pack_size)/*寫緩沖區(qū)子程序輸入?yún)?shù): aMem: 緩沖區(qū)地址aBuf: 寫數(shù)據(jù)地址輸出參數(shù): <=00 : 錯(cuò)誤XXXX : 數(shù)據(jù)項(xiàng)序號*register int s,i,width,l

14、ength,mem_i;char *buf;struct MEM_PACKET * curr_pack;s = 0;mem_data = (struct MEM_DATA *)su1_2;width = mem_data0.width;length = mem_data0.length;mem_i = mem_data0.wi;buf = (void *)(char *)su1_2 + width * mem_i);for (i=1;i<length;i+)curr_pack = (struct MEM_PACKET *)buf;if (curr_pack->len = 0)mem

15、cpy(curr_pack->packetp,aBuf,pack_size);curr_pack->len = pack_size;s = mem_i;mem_i+;if (mem_i >= length)mem_i = 1;mem_data0.wi = mem_i;break;mem_i+;if (mem_i >= length)mem_i = 1;buf = (void *)(char *)su1_2 + width);else buf = (char *)su1_2 + width*mem_i;if(i >= length)s = 0;return s;/

16、proc 文件讀函數(shù)int read_procaddr(char *buf,char *start,off_t offset,int count,int *eof,void *data)sprintf(buf,"%un",_pa(su1_2);*eof = 1;return 9;/*added*/在 8139too.c 的 rtl8139_init_module() 函數(shù)中加入以下代碼:/*add_by_liangjian for zero_copy*/put_pkt2mem_n = 0;init_mem();put_mem("data1dfadfaserty&q

17、uot;,16);put_mem("data2zcvbnm",11);put_mem("data39876543210poiuyt",21);create_proc_read_entry("nf_addr",0,NULL,read_procaddr,NULL);/*added */在 8139too.c 的 rtl8139_cleanup_module() 函數(shù)中加入以下代碼:/*add_by_liangjian for zero_copy*/del_mem();remove_proc_entry("nf_addr"

18、;,NULL);/*added*/b 用戶空間讀取緩存代碼#include <stdio.h>#include <unistd.h>#include <sys/stat.h>#include <sys/mman.h>#include <fcntl.h>#define PAGES 512#define MEM_WIDTH 1500struct MEM_DATA/int key;unsigned short width;/* 緩沖區(qū)寬度*/unsigned short length;/* 緩沖區(qū)長度*/unsigned short wti

19、mes;/* 寫進(jìn)程記數(shù),預(yù)留,為以后可以多個(gè)進(jìn)程寫*/unsigned short rtimes;/* 讀進(jìn)程記數(shù),預(yù)留,為以后可以多個(gè)進(jìn)程讀*/unsigned short wi;/* 寫指針 */unsigned short ri;/* 讀指針 */ * mem_data;struct MEM_PACKETunsigned int len;unsigned char packetpMEM_WIDTH - 4;/*sizeof(unsigned int) = 4*/ ;int get_mem(char *aMem,char *aBuf,unsigned int *size) /*讀緩沖區(qū)子

20、程序輸入?yún)?shù): aMem: 緩沖區(qū)地址aBuf: 返回?cái)?shù)據(jù)地址, 其數(shù)據(jù)區(qū)長度應(yīng)大于*緩沖區(qū)寬度*輸出參數(shù): <=00 : 錯(cuò)誤XXXX : 數(shù)據(jù)項(xiàng)序號*/*register int i,s,width,length,mem_i;char *buf;struct MEM_PACKET * curr_pack;s = 0;mem_data = (void *)aMem;width = mem_data0.width;length = mem_data0.length;mem_i = mem_data0.ri;buf = (void *)(aMem + width * mem_i);curr

21、_pack = (struct MEM_PACKET *)buf;if (curr_pack->len != 0)/* 第一個(gè)字節(jié)為0 說明該部分為空*/memcpy(aBuf,curr_pack->packetp,curr_pack->len);*size = curr_pack->len;curr_pack->len = 0;s = mem_data0.ri;mem_data0.ri+;if(mem_data0.ri >= length)mem_data0.ri = 1;goto ret;for (i=1;i<length;i+)*/mem_i+;

22、/* 繼續(xù)向后找,最糟糕的情況是把整個(gè)緩沖區(qū)都找一遍if (mem_i >= length)mem_i = 1;buf = (void *)(aMem + width*mem_i);curr_pack = (struct MEM_PACKET *)buf;if (curr_pack->len = 0)continue;memcpy(aBuf,curr_pack->packetp,curr_pack->len);*size = curr_pack->len;curr_pack->len = 0;s = mem_data0.ri = mem_i;mem_data

23、0.ri+;if(mem_data0.ri >= length)mem_data0.ri = 1;break;ret:return s;int main()char *su1_2;char receive1500;int i,j;int fd;int fd_procaddr;unsigned int size;char addr9;unsigned long ADDR;j = 0;/*open device 'mem' as a media to access the RAM*/fd=open("/dev/mem",O_RDWR);fd_procadd

24、r = open("/proc/nf_addr",O_RDONLY);read(fd_procaddr,addr,9);ADDR = atol(addr);close(fd_procaddr);printf("%u%8lxn",ADDR,ADDR);/*Map the address in kernel to user space, use mmap function*/su1_2 = mmap(0,PAGES*4*1024, PROT_READ|PROT_WRITE, MAP_SHARED, fd, AD perror("mmap"

25、);while(1)bzero(receive,1500);i = get_mem(su1_2,receive,&size);if (i != 0)j+;printf("%d:%ssize = %dn",j,receive,size);elseprintf("there have no datan");munmap(su1_2,PAGES*4*1024);close(fd);break;while(1);五.參考文獻(xiàn)1 . CHRISTIAN KURMANN, FELIX RAUCH ,THOMAS M. STRICKER.Speculative

26、 Defragmentation - Leading Gigabit Ethernet to True Zero-Copy Communication2 . ALESSANDRO RUBINI,JONATHAN CORBET. «LINUX DEVICE DRIVERS 2,O' Re3 .胡希明,毛德操.LINUX內(nèi)核源代碼情景分析,浙江大學(xué)出版社2001關(guān) 于作者:梁健,華北計(jì)算技術(shù)研究所在讀碩士研究生,研究方向:信息安全。論文開題為 主機(jī)異常入侵檢測與防御。對IDS有兩年多的研 究經(jīng)驗(yàn),熟悉linux內(nèi)核,熟悉linux c/c+ 程,對網(wǎng)絡(luò)和操作系統(tǒng)安全感興趣通過零拷

27、貝實(shí)現(xiàn)有效數(shù)據(jù)傳輸零拷貝,零開銷Sathish K. Palaniappan ,系統(tǒng)軟件工程師,EMPramod B. Nagaraja ,助理系統(tǒng)軟件工程師 ,IBM簡介:本文解釋了如何通過一種稱為零拷貝的方法來提高運(yùn)行于 Linux?和UNIX?平臺 上的I/O密集型Java? 應(yīng)用程序的性能。零拷貝不僅消除了中間緩沖區(qū)之間的冗余數(shù)據(jù) 拷貝,還減少了用戶空間和內(nèi)核空間之間的上下文切換次數(shù)。本文的標(biāo)簽:零拷貝標(biāo)記本文!發(fā)布日期:2008年9月23日級別:中級其他語言版本:三訪問情況1163次瀏覽建議:1 (查看或添加評論) 平均分(共3個(gè)評分)很多 Web應(yīng)用程序都會(huì)提供大量的靜態(tài)內(nèi)容,其數(shù)

28、量多到相當(dāng)于讀完整個(gè)磁盤的數(shù)據(jù)再將同樣的數(shù)據(jù)寫回響應(yīng)套接字(socket )。此動(dòng)作看似只需較少的CPU活動(dòng),但它的效率非常低:首先內(nèi)核讀出全盤數(shù)據(jù),然后將數(shù)據(jù)跨越內(nèi)核用戶推到應(yīng)用程序,然后應(yīng)用程序再次跨越內(nèi)核用戶將數(shù)據(jù)推回,寫出到套接字。應(yīng)用程序?qū)嶋H上在這里擔(dān)當(dāng)了一個(gè)不怎么高效的中介角色,將磁盤文件的數(shù)據(jù)轉(zhuǎn)入套接字。數(shù)據(jù)每遍歷用戶內(nèi)核一次,就要被拷貝一次,這會(huì)消耗CPU周期和內(nèi)存帶寬。幸運(yùn)的是,您可以通過一個(gè)叫 零拷貝一很貼切 一的技巧來消除這些拷貝。使用零拷貝的應(yīng)用程序要求內(nèi)核直接將數(shù)據(jù)從磁盤文件拷貝到套接字,而無需通過應(yīng)用程序。零拷貝不僅大大地提高了應(yīng)用程序的性能,而且還減少了內(nèi)核與用戶

29、模式間的上下文切換。Java 類庫通過 java.nio.channels.FileChannel中的 transferTo() 方法來在Linux和UNIX系統(tǒng)上支持零拷貝??梢允褂?transferTo()方法直接將字節(jié)從它被調(diào)用的通道上傳輸?shù)搅硗庖粋€(gè)可寫字節(jié)通道上,數(shù)據(jù)無需流經(jīng)應(yīng)用程序。 本文首先展示了通過傳統(tǒng)拷貝語義進(jìn)行的簡單文件傳輸引發(fā)的開銷,然后展示了使 用transferTo()零拷貝技巧如何提高性能。數(shù)據(jù)傳輸:傳統(tǒng)方法考慮一下從一個(gè)文件中讀出數(shù)據(jù)并將數(shù)據(jù)傳輸?shù)骄W(wǎng)絡(luò)上另一程序的場景(這個(gè)場景表述出了很多服務(wù)器應(yīng)用程序的行為,包括提供靜態(tài)內(nèi)容的Web應(yīng)用程序、FTP服務(wù)器、郵件服務(wù)

30、器等)。操作的核心在清單 1的兩個(gè)調(diào)用中(參見 下載,查找完整示例代碼的鏈接): 清單1.把字節(jié)從文件拷貝到套接字File.read(fileDesc, buf, len);Socket.send(socket, buf, len);清單1的概念很簡單,但實(shí)際上,拷貝的操作需要四次用戶模式和內(nèi)核模式間的上下文切換,而且在操作完成前數(shù)據(jù)被復(fù)制了四次。圖 1展示了數(shù)據(jù)是如何在內(nèi)部從文件移動(dòng)到套 接字的: 圖1.傳統(tǒng)的數(shù)據(jù)拷貝方法Application contextKernel contextNIC buffera DMA copy*- CPU copy圖2展示了上下文切換:這里涉及的步驟有:1.

31、 read() 調(diào)用(參見 且N)引發(fā)了一次從用戶模式到內(nèi)核模式的上下文切換。在 內(nèi)部,發(fā)出sys_read() (或等效內(nèi)容)以從文件中讀取數(shù)據(jù)。直接內(nèi)存存取(direct memory access , DMA)引擎執(zhí)行了第一次拷貝(參見 圖1),它從磁盤中讀取文 件內(nèi)容,然后將它們存儲(chǔ)到一個(gè)內(nèi)核地址空間緩存區(qū)中。2. 所需的數(shù)據(jù)被從讀取緩沖區(qū)拷貝到用戶緩沖區(qū),read()調(diào)用返回。該調(diào)用的返回引發(fā)了內(nèi)核模式到用戶模式的上下文切換(又一次上下文切換)。現(xiàn)在數(shù)據(jù)被儲(chǔ)存 在用戶地址空間緩沖區(qū)。3. send() 套接字調(diào)用引發(fā)了從用戶模式到內(nèi)核模式的上下文切換。數(shù)據(jù)被第三次拷貝,并被再次放置在

32、內(nèi)核地址空間緩沖區(qū)。但是這一次放置的緩沖區(qū)不同,該緩沖 區(qū)與目標(biāo)套接字相關(guān)聯(lián)。4. send() 系統(tǒng)調(diào)用返回,結(jié)果導(dǎo)致了第四次的上下文切換。DMA引擎將數(shù)據(jù)從內(nèi)核緩沖區(qū)傳到協(xié)議引擎,第四次拷貝獨(dú)立地、異步地發(fā)生。使用中間內(nèi)核緩沖區(qū)(而不是直接將數(shù)據(jù)傳輸?shù)接脩艟彌_區(qū))看起來可能有點(diǎn)效率低下。但是之所以引入中間內(nèi)核緩沖區(qū)的目的是想提高性能。在讀取方面使用中間內(nèi)核緩沖區(qū),可以允許內(nèi)核緩沖區(qū)在應(yīng)用程序不需要內(nèi)核緩沖區(qū)內(nèi)的全部數(shù)據(jù)時(shí),充當(dāng)預(yù)讀高速緩存(readahead cache ) ”的角色。這在所需數(shù)據(jù)量小于內(nèi)核緩沖區(qū)大小時(shí)極大地提高了性能。 在寫入方面的中間緩沖區(qū)則可以讓寫入過程異步完成。 不

33、幸的是,如果所需數(shù)據(jù)量遠(yuǎn)大于內(nèi)核緩沖區(qū)大小的話,這個(gè)方法本身可能成為一個(gè)性能瓶頸。數(shù)據(jù)在被最終傳入到應(yīng)用程序前,在磁盤、內(nèi)核緩沖區(qū)和用戶緩沖區(qū)中被拷貝了多次。 零拷貝通過消除這些冗余的數(shù)據(jù)拷貝而提高了性能。回頁首數(shù)據(jù)傳輸:零拷貝方法再次檢查 傳統(tǒng)場景,您就會(huì)注意到第二次和第三次拷貝根本就是多余的。應(yīng)用程序只是起 到緩存數(shù)據(jù)并將其傳回到套接字的作用而以,別無他用。數(shù)據(jù)可以直接從讀取緩沖區(qū)傳輸?shù)教捉幼志彌_區(qū)。transferTo()方法就能夠讓您實(shí)現(xiàn)這個(gè)操作。清單 2展示了transferTo()的方法簽名:清單 2. transferTo() 方法public void transferTo(l

34、ong position, long count, WritableByteChannel target);transferTo()方法將數(shù)據(jù)從文件通道傳輸?shù)搅私o定的可寫字節(jié)通道。在內(nèi)部,它依賴底層操作系統(tǒng)對零拷貝的支持;在 UNIX和各種Linux系統(tǒng)中,此調(diào)用被傳遞到sendfile()系統(tǒng)調(diào)用中,如清單 3所示,清單 3將數(shù)據(jù)從一個(gè)文件描述符傳輸?shù)搅肆硪粋€(gè)文件描述符:清單3. sendfile() 系統(tǒng)調(diào)用#include <sys/socket.h>ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t c

35、ount);清單1中的file.read() 和socket.send()調(diào)用動(dòng)作可以替換為一個(gè)單一的transferTo() 調(diào)用,如清單 4所示:清單4.使用transferTo()將數(shù)據(jù)從磁盤文件拷貝到套接字transferTo(position, count, writableChannel);圖3展示了使用transferTo()方法時(shí)的數(shù)據(jù)路徑:圖 3.使用 transferTo()方法的數(shù)據(jù)拷貝Application contextKernelcontextRead bufferSocket bufferNIC buffer圖4展示了使用transferTo()方法時(shí)的上下文切換:方法時(shí)的步驟有:1. transferTo()使用 清單4所示的transferTo()方法引發(fā) DMA引擎將文件內(nèi)容拷貝到一個(gè)讀取緩沖區(qū)。然后由內(nèi)核將數(shù)據(jù)拷貝到與輸出套接字相關(guān)聯(lián)的內(nèi)核緩沖區(qū)O2.數(shù)據(jù)的第三次復(fù)制發(fā)生在DMA引擎將數(shù)據(jù)從內(nèi)核套接字緩沖區(qū)傳到協(xié)議引擎時(shí)。改進(jìn)的地方:我們將上下文切換的次數(shù)從四次減少到了兩次,將數(shù)據(jù)復(fù)制的次數(shù)從四次減少到了三次(其中只有一次涉及到了CPU)。但是這個(gè)代碼尚未達(dá)到我們的零拷貝要求。如果底層網(wǎng)絡(luò)接口卡支持 收集操作 的話,那么我們就可以進(jìn)一步減少內(nèi)核的數(shù)據(jù)復(fù)制。在 Linux內(nèi)核2.4及后期版本中,套接字緩

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論