(匿名)管道:一種進程間通訊形式。把從一個進程鏈接到另外一個進程的一個數據流成爲一個管道(固定大小內核緩衝區)。
管道的限制:一、半雙工(數據只能在一個方向流動)須要雙方通訊時,要創建兩個管道;
二、只能用於共同祖先進程(具備親緣關係的進程)通訊,一般一個管道由一個進程建立,而後調用fork。spa
例如:ls | wc -w : ls進程將輸出寫到管道,wc進程從管道獲取數據.code
#include<unistd.h>
int pipe(int fd[2]); // 建立管道,返回兩個文件描述符,fd[0]表示讀端,fd[1]表示寫端.成功返回0,失敗返回-1blog
具體狀態能夠以下圖:父進程建立管道後,調用fork,子進程的fd0 fd1 也指向了管道讀寫端進程
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<string.h> 9 10 #include<signal.h> 11 #define ERR_EXIT(m)\ 12 do\ 13 {\ 14 perror(m);\ 15 exit(EXIT_FAILURE);\ 16 }while(0) //宏要求一條語句 17 int main(int argc,char*argv[]) 18 { 19 int pipefd[2]; 20 //建立管道 21 if(pipe(pipefd)==-1) 22 ERR_EXIT("pipe error"); 23 pid_t pid; 24 if((pid=fork())==-1) 25 ERR_EXIT("fork error"); 26 else if(pid==0){//子進程發送數據給父進程 27 close(pipefd[0]); 28 write(pipefd[1],"hello",5); 29 close(pipefd[1]); 30 exit(EXIT_SUCCESS); 31 } 32 close(pipefd[1]); 33 char buf[10]; 34 read(pipefd[0],buf,10); 35 printf("buf=%s\n",buf); 36 close(pipefd[0]); 37 return 0; 38 }
下面這個例子用pipe來模擬 ls | wc -w :運行兩個進程 ls進程 、 wc -w進程。 用子進程運行ls,寫數據到管道。 父進程運行wc 從管道讀數據ip
正常狀況,ls輸出到標準輸出,於是須要先進行重定向(到管道寫端)。輸出到管道。 同理 wc也同樣string
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<string.h> 9 10 #include<signal.h> 11 #define ERR_EXIT(m)\ 12 do\ 13 {\ 14 perror(m);\ 15 exit(EXIT_FAILURE);\ 16 }while(0) //宏要求一條語句 17 int main(int argc,char*argv[]) 18 { 19 int pipefd[2]; 20 if(pipe(pipefd)==-1) 21 ERR_EXIT("pipe error"); 22 pid_t pid; 23 if((pid=fork())==-1) 24 ERR_EXIT("fork error"); 25 else if(pid==0){ 26 close(pipefd[0]);//關閉管道讀端 27 dup2(pipefd[1],STDOUT_FILENO);//1指向pipefd[1], 1指向管道寫端。 標準輸出,輸出到1;無論1指向哪,都記住輸出到 1 .等效於close(oldfd); fcntl(oldfd, F_DUPFD, newfd); 28 close(pipefd[1]); 29 execlp("ls","ls",(char*)0,NULL);//若果調用失敗將執行如下內容,ls 輸出到管道寫端 30 fprintf(stderr,"error ececutr ls\n"); 31 exit(EXIT_SUCCESS); 32 } 33 close(pipefd[1]);//關閉管道寫端 34 dup2(pipefd[0],STDIN_FILENO); 35 close(pipefd[0]);//標準輸入是管道讀端 36 execlp("wc","wc","-w",(char*)0,NULL);//從標準輸入獲取 37 fprintf(stderr,"error ececutr ls\n"); 38 return 0; 39 }
補充一個例子來講明文件描述符拷貝。it
1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdlib.h> 6 #include<stdio.h> 7 #include<errno.h> 8 #include<string.h> 9 10 #include<signal.h> 11 #define ERR_EXIT(m)\ 12 do\ 13 {\ 14 perror(m);\ 15 exit(EXIT_FAILURE);\ 16 }while(0) //宏要求一條語句 17 int main(int argc,char*argv[]) 18 { 19 close(0);//0和標準輸入斷開,0指向Makefile 20 open("Makefile",O_RDONLY);//Makefile做爲標準輸入 21 close(1); 22 open("Makefile2",O_WRONLY|O_CREAT|O_TRUNC,0644);//Makefile2做爲標準輸出 23 //拷貝makefile 24 execlp("cat","cat",(char*)0,NULL);//cat不帶參數,表示將標準輸入獲取數據寫入標準輸出 25 return 0; 26 }