1. 程式人生 > >Sendfile Linux 系統中的零拷貝

Sendfile Linux 系統中的零拷貝


步驟一:sendfile系統呼叫導致檔案內容通過DMA模組被複制到核心緩衝區中。

步驟二:資料並未被複制到socket關聯的緩衝區內。取而代之的是,只有記錄資料位置和長度的描述符被加入到socket緩衝區中。DMA模組將資料直接從核心緩衝區傳遞給協議引擎,從而消除了遺留的最後一次複製。

由於資料實際上仍然由磁碟複製到記憶體,再由記憶體複製到傳送裝置,有人可能會聲稱這並不是真正的"零拷貝"。然而,從作業系統的角度來看,這就是"零拷貝",因為核心空間內不存在冗餘資料。應用"零拷貝"特性,出了避免複製之外,還能獲得其他效能優勢,例如更少的上下文切換,更少的CPU cache汙染以及沒有CPU必要計算校驗和。


現在我們明白了什麼是"零拷貝",讓我們將理論付諸實踐,編寫一些程式碼。你可以從www.xalien.org/articles/source/sfl-src.tgz處下載完整的原始碼。執行"tar -zxvf sfl-src.tgz"將原始碼解壓。執行make命令,編譯原始碼,並建立隨機資料檔案data.bin

從標頭檔案開始介紹程式碼:

/* sfl.c sendfile example program
Dragan Stancevic <
header name function / variable
-------------------------------------------------*/
#include <stdio.h> /* printf, perror */

#include <fcntl.h> /* open */
#include <unistd.h> /* close */
#include <errno.h> /* errno */
#include <string.h> /* memset */
#include <sys/socket.h> /* socket */
#include <netinet/in.h> /* sockaddr_in */
#include <sys/sendfile.h> /* sendfile */
#include <arpa/inet.h> /* inet_addr */

#define BUFF_SIZE (10*1024) /* size of the tmp buffer */

除了基本socket操作所需要的 <sys/socket.h> 和<netinet/in.h>標頭檔案外,我們還需要包含sendfile系統呼叫的原型定義,這可以在<sys/sendfile.h>標頭檔案中找到。

伺服器標誌:

/* are we sending or receiving */
if(argv[1][0] == 's') is_server++;
/* open descriptors */
sd = socket(PF_INET, SOCK_STREAM, 0);
if(is_server) fd = open("data.bin", O_RDONLY);

該程式既能以服務端/傳送方,也能以客戶端/接收方的身份執行。我們需要檢查命令列引數中的一項,然後相應的設定is_server標誌。程式中大開了一個地址族為PF_INET的流套接字;作為服務端執行時需要向客戶傳送資料,因此要開啟某個資料檔案。由於程式中是用sendfile系統呼叫來發送資料,因此不需要讀取檔案內容並存儲在程式的緩衝區內。

接下來是伺服器地址:

/* clear the memory */
memset(&sa, 0, sizeof(struct sockaddr_in));
/* initialize structure */
sa.sin_family = PF_INET;
sa.sin_port = htons(1033);
sa.sin_addr.s_addr = inet_addr(argv[2]);


將服務端地址結構清零後設置協議族、埠和IP地址。服務端的IP地址作為命令列引數傳遞給程式。埠號硬編碼為1033,選擇該埠是因為它在要求root許可權的埠範圍之上。

下面是服務端的分支程式碼:

if(is_server){
int client; /* new client socket */
printf("Server binding to [%s]\n", argv[2]);
if(bind(sd, (struct sockaddr *)&sa,sizeof(sa)) < 0){
perror("bind");
exit(errno);
}

作為服務端,需要為socket描述符分配一個地址,這是通過系統呼叫bind完成的,它將伺服器地址(sa)分配給socket描述符(sd).

if(listen(sd,1) < 0){
perror("listen");
exit(errno);
}

由於使用流套接字,必須對核心宣告接受外來連線請求的意願,並設定連線佇列的尺寸。此處將佇列長度設為1,但是通常會將該值設的高一些,用於接受已建立的連線。在老版本的核心中,該佇列被用於阻止SYN flood攻擊。由於listen系統呼叫之改為設定已建立連線的數量,該特性已被listen呼叫遺棄。核心引數tcp_max_syn_backlog承擔了保護系統不受SYN flood攻擊的功能。

if((client = accept(sd, NULL, NULL)) < 0){
perror("accept");
exit(errno);
}

accept系統呼叫從待處理的已連線佇列中選取第一個連線請求,為之建立一個新的socket。accept呼叫的返回值是新建立連線的描述符;新的socket可以用於read、write和poll/select系統呼叫。

if((cnt = sendfile(client,fd,&off, BUFF_SIZE)) < 0){
perror("sendfile");
exit(errno);
}

printf("Server sent %d bytes.\n", cnt);
close(client);

在客戶socket描述符上已經建立好連線,因此可以開始將資料傳輸至遠端系統——這時通過呼叫sendfile系統呼叫來完成。該呼叫在Linux中的原型為如下形式:

extern ssize_t
sendfile (int __out_fd, int __in_fd, off_t *offset, size_t __count) __THROW;

前兩個引數為檔案描述符,第三個引數表示sendfile開始傳輸資料的偏移量。第四個引數是打算傳輸的位元組數。為了sendfile可以使用"零拷貝“特性,網絡卡需要支援聚合操作,此外還應具備校驗和計算能力。如果你的NIC不具備這些特性,仍可以是用sendfile來發送資料,區別是核心在傳輸前會將所有緩衝區的內容合併。

移植性問題

sendfile系統呼叫的問題之一,總體上來看,是缺少標準化的實現,這與open系統呼叫類些。sendfile在Linux、Solaris或HP-UX中的實現有很大的不同。這給希望在網路傳輸程式碼中利用"零拷貝"的開發者帶來了問題。

這些實現差異中的一點在於Linux提供的sendfile,是定義為用於兩個檔案描述符之間和檔案到socket之間的傳輸介面。另一方面,HP-UX和Solaris中,sendfile只能用於檔案到socket的傳輸。

第二點差異,是Linux沒有實現向量化傳輸。Solaris和HP-UX 中的sendfile系統呼叫包含額外的引數,用於消除為待傳輸資料新增頭部的開銷。

展望

Linux中“零拷貝”的實現還遠未結束,並很可能在不久的未來發生變化。更多的功能將會被新增,例如,現在的sendfile不支援向量化傳輸,而諸如Samba和Apache這樣的伺服器不得不是用TCP_COKR標誌來執行多個sendfile呼叫。該標誌告知系統還有資料要在下一個sendfile呼叫中到達。TCP_CORK和TCP_NODELAY不相容,後者在我們希望為資料新增頭部時使用。這也正是一個完美的例子,用於說明支援向量化的sendfile將在那些情況下,消除目前實現所強制產生的多個sendfile呼叫和延遲。

當前sendfile一個相當令人不愉快的限制是它無法使用者傳輸大於2GB的檔案。如此尺寸大小的檔案,在今天並非十分罕見,不得不復制資料是十分令人失望的。由於這種情況下sendfile和mmap都是不可用的,在未來核心版本中提供sendfile64,將會提供很大的幫助。

結論

相關推薦

Sendfile Linux 系統拷貝

步驟一:sendfile系統呼叫導致檔案內容通過DMA模組被複制到核心緩衝區中。步驟二:資料並未被複制到socket關聯的緩衝區內。取而代之的是,只有記錄資料位置和長度的描述符被加入到socket緩衝區中。DMA模組將資料直接從核心緩衝區傳遞給協議引擎,從而消除了遺留的最後一次複製。由於資料實際上仍然由磁碟複

linux拷貝詳細描述

文章屬於轉載文章 這篇文章需要用到頁快取和記憶體對映的知識,所以建議先看之前的幾篇文章。 引言 傳統的 Linux 作業系統的標準 I/O 介面是基於資料拷貝操作的,即 I/O 操作會導致資料在作業系統核心地址空間的緩衝區和應用程式地址空間定義的緩衝區之間進行傳輸。這樣做最大的好處是可以

linux系統的簡單拷貝檔案程式碼

#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #inc

將windows系統主機上的檔案拷貝Linux系統;將Linux系統的檔案貼上到Windows主機

        本篇文章主要實現將windows主機上的檔案複製到Linux伺服器上,這裡為了方便演示,我舉例放在C盤中的一個test101.py檔案,現在我要將它放在Linux系統的home下的sh

老男孩教育每日一題-2017年5月12日-磁盤知識點:linux系統LVM配置實現方法?

邏輯卷管理 磁盤 每日一題 1.題目老男孩教育每日一題-2017年5月12日-磁盤知識點:linux系統中LVM配置實現方法?2.參考答案01:將一個或多個物理分區創建為一個PV# pvcreate /dev/sdb{1,2} Physical volume "/dev/sdb1" success

linux系統定時任務

linu tab 一次 腳本 lin edi 路徑 執行 表示 1、查看所有定時任務:命令:“crontab -l” 數字意思解釋如下:從左到右,依次是:分、時、日、月、星期。 2、編輯定時執行計劃:命令:"crontab -e" ,e表示edit修改的意思。 3、修

Linux 系統這樣修復 SambaCry 漏洞

windows 服務器 解決方案 linux 非官方 導讀Samba 很久以來一直是為 linux 系統上的 Windows 客戶端提供共享文件和打印服務的標準。家庭用戶,中型企業和大型公司都在使用它,它作為最佳解決方案在多種操作系統共存的環境中脫穎而出,由於廣泛使用的工具很可能發生這種情

linux 系統的 /bin /sbin /usr/bin /usr/sbin /usr/local/bin /usr/local/sbin 目錄的區別

。。 process pre this 用戶 unix table mount sent 先來段英文的: /bin This directory contains executable programs which are needed in single user

Linux 系統安裝Mysql_5.6

上傳 粘貼 啟動mysql grant ont linu chm cli char Linux 系統中安裝Mysql_5.6 安裝包下載地址(http://pan.baidu.com/s/1o8G5q

Linux系統安裝vmTools

cdr cdrom linu 是否 壓縮 進入 span pan tin 以下是,會用到的命令、遇到的問題及解釋: 在虛擬機中安裝centOS系統,因為後續安裝服務或者其他的東西,因此需要安裝vmTools,方便將文件從宿主電腦拖進虛擬機內。(我的是tar壓縮包的vmToo

Linux系統有關/dev/null和/dev/zero文件說明及實踐

linux /dev/null 特殊文件 /dev/zero Linux系統中有關/dev/null和/dev/zero文件說明提示:這個題目完全可以作為一個面試題考考運維的應聘者:面試題:請解釋Linux中/dev/null和/dev/zero兩個文件的作用和區別。在類Unix操作系統中,

運維學習之Linux系統的文件傳輸、歸檔、壓縮

linux不同系統之間的文件傳輸1.文件歸檔1.文件歸檔,就是把多個文件變成一個歸檔文件2.tar c ##創建 f ##指定歸檔文件名稱 t ##顯示歸檔文件中的內容 r ##向歸檔文件中添加文件 --get ##取出單個文件 --delete ##刪除單個文件 x ##取出歸檔文件中的所有內容

Linux系統如何查看日誌信息

日誌文件 系統日誌 楊書凡 日誌文件是用於記錄Linux系統中各種運行消息的文件,不同的日誌文件記載了不同類型的信息,對於診斷和解決系統中的問題很有幫助分析日誌文件 日誌數據主要包括三種類型:內核及系統日誌、用戶日誌、程序日誌 #對於大多數的文本格式的日誌文件,使用tail、more、l

Linux系統修改/etc/profile文件的方法

linux在Linux系統中etc/profile文件一般是不能更改的,想要更改etc/profile文件就要用一些特殊的技巧進行Linux文件修改。本文就來介紹一下Linux系統中修改/etc/profile文件的方法:etc/profile文件是只讀的,直接用vi或gedit打開修改後是無法保存的。要修改

Linux系統svn服務器設置開機啟動

數據庫 檢查 reat version 打開端口 rest grep 建立 標簽 安裝完svn服務器後雖然好用但是因為經常重啟Linux服務器,每次重啟完就要去手動啟動svn服務器,很是麻煩,於是在網上找了一些方法後,自己把svn服務器設置成開機啟動 步驟一:安裝svn服務

Linux系統終端的入口

配置 bash 需求:登陸通過SSH登陸Linux主機,主機只能執行特定腳本或程序,如何約束?首先配置/etc/bash.bashrc 該文件每次打開新的shell都會執行該文件;添加執行腳本或程序路徑到bash.bashrc文件;對於腳本或程序,不能有退出程序的語句,異常情況下也要保持在腳本或程序裏

Linux系統實現CA

linux、創建ca前言 CA是證書的簽發機構,它是PKI的核心。CA是負責簽發證書、認證證書、管理已頒發證書的機關。它要制定政策和具體步驟來驗證、識別用戶身份,並對用戶證書進行簽名,以確保證書持有者的身份和公鑰的擁有權。。 CA 也擁有一個證書(內含公鑰)和私鑰。網上的公眾用戶通

Linux系統安裝MySQL數據庫操作手冊

linux mysql數據庫 Linux系統中MySQL數據庫安裝手冊一、安裝概述: 在Linux操作系統中安裝MySQL數據庫是一個我們必須要掌握的一門技術,也決定了你以後找工作的薪資待遇,所以你知道它的厲害了吧!學會安裝只是第一步,你還得學好數據庫的基本操作,以及搭建一個數據庫的主從配置等等

Linux系統MySQL數據庫“主從”配置

linux mysql數據庫主從配置 MySQL數據庫“主從”配置一、配置概述: 在Linux操作系統中配置MySQL數據庫的主從復制是很重要的,為什麽這樣說呢!是因為在你搭建一個服務器以後你配置了2臺數據庫,一主一從。2臺數據庫配置好以後,當其中一臺數據庫被攻擊以後,你被攻擊的這臺數據庫的數據

linux系統如何進入退出vim編輯器的方法及區別

sig bili 編輯器 html enter mil erl convert dstat 在linux家族中,vim編輯器是系統自帶的文本編輯器,其功能強大自不必說了。 偶有小白,剛接觸linux,要修改某個文本文件,不可能像WINDOWS那樣操作