日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

Linux "零拷贝" sendfile函数中文说明及实际操作分析

發布時間:2023/12/15 综合教程 38 生活家
生活随笔 收集整理的這篇文章主要介紹了 Linux "零拷贝" sendfile函数中文说明及实际操作分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Sendfile函數說明

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

sendfile()是作用于數據拷貝在兩個文件描述符之間的操作函數.這個拷貝操作是內核中操作的,所以稱為"零拷貝".sendfile函數比起read和write函數高效得多,因為read和write是要把數據拷貝到用戶應用層操作.

參數說明:
out_fd 是已經打開了,用于寫操作(write)的文件描述符;
in_fd 是已經打開了,用于讀操作(read)的文件描述符;
offset 偏移量;表示sendfile函數從in_fd中的哪一偏移量開始讀取數據.如果是零表示從文件的開始讀,否則從相應的便宜量讀取.如果是循環讀取的時候,下一次offset值應為sendfile函數返回值加上本次的offset的值.
count是在兩個描述符之間拷貝的字節數(bytes)

返回值:
如果成功的拷貝,返回寫操作到out_fd的字節數,錯誤返回-1,并相應的設置error信息.

EAGAIN 無阻塞I/O設置O_NONBLOCK時,寫操作(write)阻塞了.
EBADF 輸出或者輸入的文件描述符沒有打開.
EFAULT 錯誤的地址.
EINVAL 描述符不可用或者鎖定了,或者用mmap()函數操作的in_fd不可用.
EIO 當讀取(read)in_fd時發生未知錯誤.
ENOMEM 讀(read)in_fd時內存不足.

由于想再提升原有系統中文件傳輸模塊的速度,并減少系統資源占用,進行了一次sendfile()的性能測試,但失敗了.不過還是將它用在了模塊中.記錄一下這次失改的微調測試.

運行平臺: 客戶機與服務器均為P4計算機,IDE硬盤; Fedora5發行版; 百兆局域網;

接收端程序如下:

FILE *fp = fopen(FILENAME,"wb");

while((len = recv(sockfd, buff, sizeof(buff), 0)) > 0)
{
fwrite(buffer, 1, len, fp);
}
fclose(fp);

A. 發送端傳統方式代碼段如下:

fd = open(FILENAME, O_RDONLY);
while((len =read(fd, buff, sizeof(buff))) >0) 
{
send(sockfd, buff, len ,0);
}
close(fd); 

由于我磁盤分區時指定的塊大小為4096,為了最優讀取磁盤數據,buff大小設為4096字節.但在測試中發現設為1024或8192不會對傳輸速度帶來影響.

文件大小:9M; 耗時:0.71 - 0.76秒;
文件大小:32M; 耗時:2.64 - 2.68秒;
文件大小:64M; 耗時:5.36 - 5.43秒;

B. 使用sendfile()傳輸代碼段.

off_t offset = 0;
stat(FILENAME, &filestat);

fd = open(FILENAME, O_RDONLY);
sendfile(sockfd, fd, &offset, filestat.st_size) );
close(fd); 

文件大小:9M; 耗時:0.71 - 1.08秒;
文件大小:32M; 耗時:2.66 - 2.74秒;
文件大小:64M; 耗時:5.43 - 6.64秒;

似乎還略有下降.根據sendfile的man手冊,我在使用該函數前調用了

int no = 1;
printf("%d
", setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, (char*)&no, sizeof(int)) );

文件大小:9M; 耗時:0.72 - 0.75秒;
文件大小:32M; 耗時:2.66 - 2.68秒;
文件大小:64M; 耗時:5.38 - 5.60秒;

這樣似乎達到了傳統方式的速度?!不管哪種環境下,我用ethereal抓包顯示每一個tcp包的playload部分最大也通常是1448字節.

看來我的測試沒有體現出"應用層數據的兩次拷貝帶來很大的消耗"這一說法.如果按照存在就是有理的說法的話,那我想sendfile()在兩種情況下才體現優勢,但我卻沒有環境測試:

1. 大并發量的文件服務器或HTTP服務器;
2. 內存資源緊張的嵌入式系統;

另外,網絡上大量的關于tcp選項中的TCP_CORK描述已經過時.在man手冊中早已提到該參數可以與TCP_NODELAY結合使用了.只是,只要設置了TCP_NODELAY選項后,不管是否設置TCP_CORK,包都會立即發出.

補充:
TCP_NODELAY和TCP_CORK基本上控制了包的“Nagle化”,Nagle化在這里的含義是采用Nagle算法把較小的包組裝為更大的幀。 John Nagle是Nagle算法的發明人,后者就是用他的名字來命名的,他在1984年首次用這種方法來嘗試解決福特汽車公司的網絡擁塞問題(欲了解詳情請參看IETF RFC 896)。他解決的問題就是所謂的silly window syndrome ,中文稱“愚蠢窗口癥候群”,具體含義是,因為普遍終端應用程序每產生一次擊鍵操作就會發送一個包,而典型情況下一個包會擁有一個字節的數據載荷以及40個字節長的包頭,于是產生4000%的過載,很輕易地就能令網絡發生擁塞,。 Nagle化后來成了一種標準并且立即在因特網上得以實現。它現在已經成為缺省配置了,但在我們看來,有些場合下把這一選項關掉也是合乎需要的。

現在讓我們假設某個應用程序發出了一個請求,希望發送小塊數據。我們可以選擇立即發送數據或者等待產生更多的數據然后再一次發送兩種策略。如果我們馬上發送數據,那么交互性的以及客戶/服務器型的應用程序將極大地受益。例如,當我們正在發送一個較短的請求并且等候較大的響應時,相關過載與傳輸的數據總量相比就會比較低,而且,如果請求立即發出那么響應時間也會快一些。以上操作可以通過設置套接字的TCP_NODELAY選項來完成,這樣就禁用了 Nagle算法。

另外一種情況則需要我們等到數據量達到最大時才通過網絡一次發送全部數據,這種數據傳輸方式有益于大量數據的通信性能,典型的應用就是文件服務器。應用Nagle算法在這種情況下就會產生問題。但是,如果你正在發送大量數據,你可以設置TCP_CORK選項禁用Nagle化,其方式正好同 TCP_NODELAY相反(TCP_CORK 和 TCP_NODELAY 是互相排斥的)。下面就讓我們仔細分析下其工作原理。

假設應用程序使用sendfile()函數來轉移大量數據。應用協議通常要求發送某些信息來預先解釋數據,這些信息其實就是報頭內容。典型情況下報頭很小,而且套接字上設置了TCP_NODELAY。有報頭的包將被立即傳輸,在某些情況下(取決于內部的包計數器),因為這個包成功地被對方收到后需要請求對方確認。這樣,大量數據的傳輸就會被推遲而且產生了不必要的網絡流量交換。

但是,如果我們在套接字上設置了TCP_CORK(可以比喻為在管道上插入“塞子”)選項,具有報頭的包就會填補大量的數據,所有的數據都根據大小自動地通過包傳輸出去。當數據傳輸完成時,最好取消TCP_CORK 選項設置給連接“拔去塞子”以便任一部分的幀都能發送出去。這同“塞住”網絡連接同等重要。

總而言之,如果你肯定能一起發送多個數據集合(例如HTTP響應的頭和正文),那么我們建議你設置TCP_CORK選項,這樣在這些數據之間不存在延遲。能極大地有益于WWW、FTP以及文件服務器的性能,同時也簡化了你的工作。

from:http://www.linuxdiyf.com/viewarticle.php?id=69189

總結

以上是生活随笔為你收集整理的Linux "零拷贝" sendfile函数中文说明及实际操作分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。