linux網路程式設計九:splice函式,高效的零拷貝
最近在看《linux高效能伺服器程式設計》,在此做個日記,以激勵自己,同時分享於有需要的朋友。
1. splice函式
#include <fcntl.h>
ssize_t splice(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, unsigned int flags);
splice用於在兩個檔案描述符之間移動資料, 也是零拷貝。
fd_in引數是待輸入描述符。如果它是一個管道檔案描述符,則off_in必須設定為NULL;否則off_in表示從輸入資料流的何處開始讀取,此時若為NULL,則從輸入資料流的當前偏移位置讀入。
fd_out/off_out與上述相同,不過是用於輸出。
len引數指定移動資料的長度。
flags引數則控制資料如何移動:
- SPLICE_F_NONBLOCK:splice 操作不會被阻塞。然而,如果檔案描述符沒有被設定為不可被阻塞方式的 I/O ,那麼呼叫 splice 有可能仍然被阻塞。
- SPLICE_F_MORE:告知作業系統核心下一個 splice 系統呼叫將會有更多的資料傳來。
- SPLICE_F_MOVE:如果輸出是檔案,這個值則會使得作業系統核心嘗試從輸入管道緩衝區直接將資料讀入到輸出地址空間,這個資料傳輸過程沒有任何資料拷貝操作發生。
2. 使用splice時, fd_in和fd_out中必須至少有一個是管道檔案描述符。
呼叫成功時返回移動的位元組數量;它可能返回0,表示沒有資料需要移動,這通常發生在從管道中讀資料時而該管道沒有被寫入的時候。
失敗時返回-1,並設定errno
3. 程式碼:通過splice將客戶端的內容讀入到管道中, 再從管道中讀出到客戶端,從而實現高效簡單的回顯服務。整個過程未執行recv/send,因此也未涉及使用者空間到核心空間的資料拷貝。
//使用splice實現的回顯伺服器
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
int main(int argc, char **argv)
{
if (argc <= 2) {
printf("usage: %s ip port\n", basename(argv[0]));
return 1;
}
const char *ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET, ip, &address.sin_addr);
int sock = socket(PF_INET, SOCK_STREAM, 0);
assert(sock >= 0);
int reuse = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
int ret = bind(sock, (struct sockaddr*)&address, sizeof(address));
assert(ret != -1);
ret = listen(sock, 5);
assert(ret != -1);
struct sockaddr_in client;
socklen_t client_addrlength = sizeof(client);
int connfd = accept(sock, (struct sockaddr*)&client, &client_addrlength);
if (connfd < 0) {
printf("errno is: %s\n", strerror(errno));
}
else {
int pipefd[2];
ret = pipe(pipefd); //建立管道
assert(ret != -1);
//將connfd上的客戶端資料定向到管道中
ret = splice(connfd, NULL, pipefd[1], NULL,
32768, SPLICE_F_MORE | SPLICE_F_MOVE);
assert(ret != -1);
//將管道的輸出定向到connfd上
ret = splice(pipefd[0], NULL, connfd, NULL,
32768, SPLICE_F_MORE | SPLICE_F_MOVE);
assert(ret != -1);
close(connfd);
}
close(sock);
return 0;
}
相關文章
- 伺服器程式設計——函式splice實現零拷貝使用解釋伺服器程式設計函式
- 使用splice函式實現0拷貝的回顯伺服器函式伺服器
- C++拷貝建構函式(深拷貝,淺拷貝)C++函式
- Java零拷貝一步曲——Linux 中的零拷貝技術JavaLinux
- Linux 和 Java 的零拷貝LinuxJava
- 拷貝建構函式函式
- 拷貝建構函式的作用函式
- 零拷貝原理
- 拷貝建構函式中的陷阱函式
- [Linux]Linux中的零拷貝技術(一)Linux
- 拷貝建構函式(比較全的)函式
- 淺析Linux中的零拷貝技術Linux
- Java NIO - 零拷貝Java
- Linux網路程式設計--初等網路函式介紹(TCP)(轉)Linux程式設計函式TCP
- MySQL的零拷貝技術MySql
- 【Linux網路程式設計】Socket Api函式Linux程式設計API函式
- C++拷貝建構函式詳解C++函式
- C++ 拷貝建構函式詳解C++函式
- 框架篇:Linux零拷貝機制和FileChannel框架Linux
- 建構函式,拷貝賦值函式的N種呼叫情況函式賦值
- linux 帶路徑拷貝檔案Linux
- C++之Big Three:拷貝構造、拷貝賦值、解構函式探究C++賦值函式
- 聊聊訊息佇列高效能的祕密——零拷貝技術佇列
- 淺拷貝與深拷貝程式碼(javascript)JavaScript
- Linux網路程式設計--完整的讀寫函式(轉)Linux程式設計函式
- C++複製控制:拷貝建構函式C++函式
- C++中建構函式,拷貝建構函式和賦值函式的詳解C++函式賦值
- c/c++ 拷貝控制 建構函式的問題C++函式
- linux程式設計之pipe()函式Linux程式設計函式
- Linux Shell程式設計(29)——函式Linux程式設計函式
- Linux 拷貝命令之高階拷貝scp命令詳解Linux
- Linux 下拷貝目錄及打包壓縮拷貝Linux
- Linux零拷貝技術,看完這篇文章就懂了Linux
- 深入理解零拷貝技術
- C++/CLI思辨錄之拷貝建構函式C++函式
- 自己寫的unix檔案拷貝指令cp實現函式函式
- C語言實現字串拷貝函式的幾種方法C語言字串函式
- 跨網路拷貝檔案的簡單實踐