今天繼續研究linux系統編程,繼上次對信號進行研究以後,此次開始一個新的章節-----管道,在正式開始以前,先把今天讓本身很激動的事說一下,小小的興奮,通過下週後本身的創業產品用戶量就有一個質的飛越了,百萬級的,雖然說離最終的目標還有很遠,可是,這說明本身團隊最近幾個月的辛苦付出是值得的,也讓本身對此次的創業更加有期待了,小小驕傲一下,個人學習任務還得繼續堅持,誰叫咱是搞技術的呢,言歸正傳,正入正題:html
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1)//建立一個管道以後,就會獲得兩個文件描述符 ERR_EXIT("pipe error"); pid_t pid; pid = fork();//建立父子進程來演示數據通信的目的 if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) {//子進程發送數據 close(pipefd[0]);//關閉子進程管道的讀端,由於沒有用 write(pipefd[1], "hello", 5);//向子進程管道的寫端傳入數據 close(pipefd[1]);//傳遞完以後將其關掉 exit(EXIT_SUCCESS); } //父進程讀取數據 close(pipefd[1]);//關閉父進程的寫端,由於沒有用 char buf[10] = {0}; read(pipefd[0], buf, 10);//從管道的讀端讀入數據 close(pipefd[0]);//關閉管道的讀端 printf("buf=%s\n", buf); return 0; }
編譯運行:linux
這個經過管道達到進程間傳遞數據的例子比較簡單,下面用程序來模擬下面的這個shell命令的效果:web
咱們能夠用子進程來運行ls,父進程來運行wc -w命令,具體代碼以下:shell
第一步:編程
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1) ERR_EXIT("pipe error"); pid_t pid; pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) {//子進程運行ls命令, execlp("ls", "ls", NULL); fprintf(stderr, "error execute ls\n"); exit(EXIT_FAILURE); } //父進程運行wc -w命令 execlp("wc", "wc", "-w", NULL); fprintf(stderr, "error execute wc\n");//若是執行execlp運行失敗了,纔會執行到這 exit(EXIT_FAILURE); }
【說明】:關於execlp函數的使用,能夠參考博文:http://www.cnblogs.com/webor2006/p/3507913.html函數
第二步,重定向文件描述符,這是實現的關鍵:學習
由於ls命令標準是輸出到標準輸出設備(屏幕)當中,wc命令是從標準輸入設備獲取數據,而如今,咱們但願ls命令輸出到管道的寫端,而wc命令是從管道的讀端獲取數據,那該怎麼辦呢?文件描述符的複製既可達到這個目的,具體代碼以下:spa
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { int pipefd[2]; if (pipe(pipefd) == -1) ERR_EXIT("pipe error"); pid_t pid; pid = fork(); if (pid == -1) ERR_EXIT("fork error"); if (pid == 0) {//子進程運行ls命令, dup2(pipefd[1], STDOUT_FILENO);//將標準輸出複製到管道的寫端,也就是說標準輸出定位到了管道的寫端 close(pipefd[1]);//這時管道的讀寫端都沒用了,將其關閉 close(pipefd[0]); execlp("ls", "ls", NULL);//這時ls輸出則爲管道的寫端了,因爲文件描述符重定向了 fprintf(stderr, "error execute ls\n"); exit(EXIT_FAILURE); } //父進程運行wc -w命令 dup2(pipefd[0], STDIN_FILENO);//將標準輸入重定向管道的讀端,因此wc命令這時就會從管道的讀端來獲取數據嘍 close(pipefd[0]); close(pipefd[1]); execlp("wc", "wc", "-w", NULL); fprintf(stderr, "error execute wc\n");//若是執行execlp運行失敗了,纔會執行到這 exit(EXIT_FAILURE); }
編譯運行:3d
下面再來看一個有關文件描述符複製的程序,先看效果,再來分析其原理:code
#include <unistd.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/types.h> #include <fcntl.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #include <signal.h> #include <sys/time.h> #define ERR_EXIT(m) \ do \ { \ perror(m); \ exit(EXIT_FAILURE); \ } while(0) int main(int argc, char *argv[]) { close(0); open("Makefile", O_RDONLY); close(1); open("Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644); execlp("cat", "cat", NULL); return 0; }
編譯運行:
爲啥能實現文件的拷貝效果呢?我們來分析一下程序:
默認狀況下:
而下面這句代碼事後:
close(0);
open("Makefile", O_RDONLY);
close(1);
open("Makefile2", O_WRONLY | O_CREAT | O_TRUNC, 0644);
而最後一句關鍵代碼以下:
execlp("cat", "cat", NULL);
咱們一般用cat能夠查看一個文件內容:
可是,若是cat不帶參數,那是什麼意思呢?
如效果所示,不帶參數的cat命令其實是從標準輸入獲取數據,寫入到標準輸出當中,因此也就是從Makefile文件獲取數據,寫入到Makefile2文件當中,若是Makefile2文件不存在則會主動建立一個,因此就實現了一個cp命令嘍,是否是頗有技巧。
【說明】:關於文件描述符的複製,能夠參考博文:http://www.cnblogs.com/webor2006/p/3498443.html
好了,今天的內容學到這,雖然說內容很少,可是得好好理解,下回見!!