1. <dd id="erndk"></dd>
                1. 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 &…

                  目錄
                  • 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

                  贊(0)
                  關注微信小程序
                  程序員編程王-隨時隨地學編程

                  掃描二維碼或查找【程序員編程王】

                  可以隨時隨地學編程啦!

                  技術文章導航 更多>
                  国产在线拍揄自揄视频菠萝

                        1. <dd id="erndk"></dd>