Linux高級I/O函數 tee
互聯網 2022/5/2 7:16:15
- tee簽名
- tee和splice的區別
- tee示例
- 參考
tee() 在兩個管道文件描述符之間復制數據,也是重要的零拷貝技術之一。tee不消耗數據,因此源文件描述符上的數據仍然可以用于后續的讀操作。
tee簽名
#define _GNU_SOURCE /* See feature_test_macros(7) */ #include <fcntl.h> ssize_t tee(int fd_in, int fd_out, size_t len, unsigned int flags);
參數
- fd_in 待輸入數據的文件描述符,必須是管道文件。
- fd_out 待輸出數據的文件描述符,必須是管道文件。
- len 賦值的數據長度(字節數)
- flags 修飾標志,跟splice(2)/vmsplice(2) 共享命名空間:
1)SPLICE_F_MOVE 當前對tee沒有效果。
2)SPLICE_F_NONBLOCK 非阻塞的I/O操作,實際效果還會受文件描述符本身的阻塞狀態的影響。
3)SPLICE_F_MORE當前對tee沒有效果。
4)SPLICE_F_GIFT 對tee沒有效果。
返回值
成功時,返回兩個文件描述符之間復制的數據量(字節數)。返回0表示沒有復制任何數據,可能碰到EOF。失敗時,返回-1,并設置errno。
tee和splice的區別
tee類似于splice,都用于兩個fd之間數據拷貝。區別在于:
1)對參數fd的要求
splice要求2個fd中至少必須有一個fd是管道文件;
tee要求兩個fd都是管道文件。
2)對fd數據的消耗
splice是兩個fd之間數據移動,splice會消耗fd數據;
tee是兩個fd之間數據復制,tee不會消耗fd數據。
3)flags參數
Linux2.6.21以前,SPLICE_F_MOVE 對splice有效果,之后沒效果。SPLICE_F_NONBLOCK 和SPLICE_F_MORE都對splice有效果;
只有SPLICE_F_NONBLOCK 才對tee有效果;
tee示例
利用tee和splice,同時輸出數據到終端和文件。
注意:splice會消耗數據,因此,并不能同時將數據從管道pipefd_file移動到終端和文件,只能選一個;否則,會阻塞。
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <libgen.h> #include <assert.h> /** * Run command: * $ ./a.out tee_out.txt */ int main(int argc, char* argv[]) { if (argc != 2) { printf("usage: %s <file>\n", basename(argv[0])); return 1; } int filefd = open(argv[1], O_CREAT | O_TRUNC | O_WRONLY, 0666); assert(filefd >= 0); int pipefd_stdout[2]; int ret = pipe(pipefd_stdout); assert(ret != -1); int pipefd_file[2]; ret = pipe(pipefd_file); assert(ret != -1); while (1) { /* 將標準輸入內容輸入管道pipe_stdout */ ssize_t res = splice(STDIN_FILENO, NULL, pipefd_stdout[1], NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE); if (res == 0) { printf("read EOF from stdin\n"); break; } assert(res != -1); /* 將管道 pipefd_stdout 輸出復制到 pipefd_file */ res = tee(pipefd_stdout[0], pipefd_file[1], 32768, SPLICE_F_NONBLOCK); assert(res != -1); /* 將管道 pipefd_file 輸出定向到文件描述符filefd 上 */ res = splice(pipefd_file[0], NULL, filefd, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE); assert(res != -1); /* 屏蔽下面這段代碼, 防止阻塞 */ /* 將管道 pipefd_file 輸出定向到標準輸出上. 之前已經對pipe_file[0]用過splice, 會消耗其數據, 因此第二次調用不會有數據, 而且程序會阻塞到這里等待pipefd_file[0] 數據 */ // res = splice(pipefd_file[0], NULL, STDOUT_FILENO, NULL, 32768, SPLICE_F_MORE | SPLICE_F_MOVE); // assert(res != -1); printf("one loop\n"); } close(filefd); close(pipefd_stdout[0]); close(pipefd_stdout[1]); close(pipefd_file[0]); close(pipefd_file[1]); return 0; }
參考
《Linux高性能服務器編程》

關于找一找教程網
本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。
本站提供了軟件編程、網站開發技術、服務器運維、人工智能等等IT技術文章,希望廣大程序員努力學習,讓我們用科技改變世界。
[Linux高級I/O函數 tee]http://www.yachtsalesaustralia.com/tech/detail-318702.html
- 2022-05-19Linux設置開機自啟動腳本
- 2022-05-19linux及windows下查看進程及端口占用
- 2022-05-19linux 下搭建svn 并且使用鉤子hook更新到指定目錄
- 2022-05-19linux中的重定向符和管道(<,><<,>>,|)
- 2022-05-19Linux環境下Bochs軟件安裝以及可能遇到的問題
- 2022-05-19Linux環境下Python編程注意事項
- 2022-05-19linux 服務器后臺不中斷運行jar
- 2022-05-19linux安裝datax +datax-web踩坑總結
- 2022-05-19linux驅動學習筆記(四)內核配置與編譯
- 2022-05-19Jenkins-Windows環境修改主目錄路徑