隨筆-86  評論-33  文章-0  trackbacks-0

          我們平時通過網(wǎng)絡(luò)發(fā)送文件時會用到的兩個系統(tǒng)調(diào)用:
          read(file, tmp_buf, len);
          write(socket, tmp_buf, len);

          調(diào)用過程示意圖如下:

          在用戶空間調(diào)用 read() 讀取文件時發(fā)生兩次內(nèi)存拷貝:

          1. DMA引擎將文件讀取到內(nèi)核的文件緩沖區(qū)
          2. 調(diào)用返回用戶空間時將內(nèi)核的文件緩沖區(qū)的數(shù)據(jù)復(fù)制到用戶空間的緩沖區(qū)

          接著調(diào)用 write() 把數(shù)據(jù)寫入 socket 時,又發(fā)生了兩次內(nèi)存拷貝:

          1. 將用戶空間的緩沖區(qū)的數(shù)據(jù)復(fù)制到內(nèi)核的 socket 緩沖區(qū)
          2. 將內(nèi)核 socket 緩沖區(qū)的數(shù)據(jù)復(fù)制到網(wǎng)絡(luò)協(xié)議引擎

          也就是說,在整個文件發(fā)送的過程中,發(fā)生了四次內(nèi)存拷貝。
          然后,數(shù)據(jù)讀取到用戶空間后并沒有做過任何加工處理,因此通過網(wǎng)絡(luò)發(fā)送文件時,根本沒有必要把文件內(nèi)容復(fù)制到用戶空間。

          于是引入了 mmap():
          tmp_buf = mmap(file, len);
          write(socket, tmp_buf, len);

          調(diào)用過程示意圖:

          1. 調(diào)用 mmap() 時會將文件直接讀取到內(nèi)核緩沖區(qū),并把內(nèi)核緩沖區(qū)直接共享到用戶空間
          2. 調(diào)用 write() 時,直接將內(nèi)核緩沖區(qū)的數(shù)據(jù)復(fù)制到網(wǎng)絡(luò)協(xié)議引擎

          這樣一來,就少了用戶空間和內(nèi)核空間之間的內(nèi)存復(fù)制了。
          這種方式會有個問題,當(dāng)前進(jìn)程在調(diào)用 write() 時,另一個進(jìn)程把文件清空了,程序就會報出 SIGBUS 類型錯誤。

          Linux Kernel 2.1 引進(jìn)了 sendfile(),只需要一個系統(tǒng)調(diào)用來實現(xiàn)文件發(fā)送。
          sendfile(socket, file, len);

          調(diào)用過程示意圖:

          1. 調(diào)用 sendfile() 時會直接在內(nèi)核空間把文件讀取到內(nèi)核的文件緩沖區(qū)
          2. 將內(nèi)核的文件緩沖區(qū)的數(shù)據(jù)復(fù)制到內(nèi)核的 socket 緩沖區(qū)中
          3. 將內(nèi)核的 socket 緩沖區(qū)的數(shù)據(jù)復(fù)制到網(wǎng)絡(luò)協(xié)議引擎

          從性能上看,這種方式只是少了一個系統(tǒng)調(diào)用而已,還是做了3次拷貝操作。

          Linux Kernel 2.4 改進(jìn)了 sendfile(),調(diào)用接口沒有變化:
          sendfile(socket, file, len);

          調(diào)用過程示意圖:

          1. 調(diào)用 sendfile() 時會直接在內(nèi)核空間把文件讀取到內(nèi)核的文件緩沖區(qū)
          2. 內(nèi)核的 socket 緩沖區(qū)中保存的是當(dāng)前要發(fā)送的數(shù)據(jù)在內(nèi)核的文件緩沖區(qū)中的位置和偏移量
          3. DMA gather copy 將內(nèi)核的文件緩沖區(qū)的數(shù)據(jù)復(fù)制到網(wǎng)絡(luò)協(xié)議引擎

          這樣就只剩下2次拷貝啦。

          在許多 http server 中,都引入了 sendfile 的機(jī)制,如 nginx、lighttpd 等,它們正是利用 sendfile() 這個特性來實現(xiàn)高性能的文件發(fā)送的。

          posted on 2011-12-29 21:32 Derek.Guo 閱讀(706) 評論(0)  編輯  收藏 所屬分類: Linux/Unix
          MSN:envoydada@hotmail.com QQ:34935442
          主站蜘蛛池模板: 惠来县| 长泰县| 探索| 潼南县| 肃南| 西安市| 梁平县| 英吉沙县| 视频| 黎城县| 行唐县| 会东县| 酒泉市| 无极县| 甘洛县| 无棣县| 凌海市| 加查县| 高淳县| 同心县| 高唐县| 宁晋县| 南丰县| 疏附县| 峡江县| 比如县| 勃利县| 南部县| 澳门| 阿克苏市| 资中县| 修水县| 秭归县| 金沙县| 汉阴县| 白玉县| 鹤山市| 陕西省| 黔西| 枝江市| 闸北区|