7.程序間通訊:匿名管道pipe
阿新 • • 發佈:2018-11-12
匿名管道pipe
1.管道的概念 本質: 核心緩衝區 偽檔案-不佔用磁碟空間 特點:兩部分 讀端,寫端,對應兩個檔案描述符 資料寫端流入,讀端流出 操作管道的程序被銷燬後,管道自動被釋放 管道預設是阻塞的 2.管道的原理 內部實現方式:環形佇列 特點:先進先出,不能操作中間資料 緩衝區大小: 預設4K 3.管道侷限性 佇列: 資料只能讀取一次,不能重複讀取 半雙工: 資料傳輸的方向是單向流動的,因此必須有一對pipe 匿名管道:僅適用於有血緣關係的程序 4.建立匿名管道 int pipe(int pipefd[2]); 0-讀端 1-寫端 思考題: 單個程序能否使用管道完成讀寫操作?答:可以 父子程序間通訊是否需要sleep函式?答:不需要,因為[管道]是阻塞的 5.管道的讀寫行為** 讀操作 1.有資料:read-正常都,返回讀出的位元組數 2.無資料: [1]寫端全部關閉 read解除阻塞,返回0 相當於讀檔案讀到了尾部 [2]沒有全部關閉 read阻塞 寫操作 1.讀端全部關閉(重點) 管道破裂,程序被終止(核心給當前程序傳送SIGPIPE訊號) 2.讀端沒有全部關閉 緩衝區寫滿了:write阻塞 緩衝區沒滿:write繼續寫 6.檢視管道緩衝區大小 命令:ulimit -a # pipe 函式:fpathconf # _PC_PIPE_BUF long size=fpathconf(fd[0],_PC_PIPE_BUF); //測試管道緩衝區大小 7.設定管道[非阻塞]屬性 獲取原來的flags: int flags=fcntl(fd[0],F_GETFL); flag|=O_NONBLOCK; 設定新的flags:fcntl(fd[0],F_SETFL,flags);
案例1:ps aux|grep bash
程式功能:父子程序間通訊實現ps aux|grep bash ps aux|grep bash實現思路: 1.父子程序:ps aux和grep bash 2.ps aux程序將輸出資料寫到管道中(要進行重定向) dup2(fd[1],STDOUT_FILENO); 3.grep bash從管道中讀取資料(要進行重定向) dup2(fd[0],STDIN_FILENO); int main(){ int fd[2]; if(pipe(fd)==-1){ perror("pipe"); exit(1); } pid_t pid=fork(); if(pid>0){ //父程序 ps aux close(fd[0]); //關閉"read" //不是寫到STDOUT_FILENO,而是寫入fd[1] dup2(fd[1],STDOUT_FILENO); //STDOUT_FILENO檔案描述符,重定向到"write"端(fd[1]) execlp("ps","ps","aux",NULL); close(fd[1]); } if(pid==0){//子程序 grep bash close(fd[1]); //關閉"close" //不從STDIN_FILENO中read,而是從管道fd[0]中read dup2(fd[0],STDIN_FILENO);//STDIN_FILENO檔案描述符,重定向到"read"端(fd[0]) execlp("grep","grep","bash","--color=auto",NULL); close(fd[0]); } return 0; } dup2(fd[1],STDOUT_FILENO); 解讀: STDOUT_FILENO檔案描述符,重定向為指向fd[1](作為write端)
案例2:ps aux|grep bash
程式功能:兄弟程序間通訊實現ps aux|grep bash
int main(){
int fd[2];
if(pipe(fd)==-1){
perror("pipe");
exit(1);
}
int i;
pid_t pid;
for(i=0;i<2;i++){ //父程序建立2個子程序用於通訊
pid=fork();
if(pid==0)
break;
}
if(i==0){ //子程序1
close(fd[1]); //close 'write'
dup2(fd[0],STDIN_FILENO);
execl("/bin/grep","grep","bash","--color=auto",NULL);
close(fd[0]);
}
if(i==1){ //子程序2
close(fd[0]); //close 'read'
dup2(fd[1],STDOUT_FILENO);
execl("/bin/ps","ps","aux",NULL);
close(fd[1]);
}
if(i==2){ //父程序
close(fd[0]);
close(fd[1]);
pid_t w_pid;
int status;
while((w_pid=waitpid(-1,&status,WNOHANG))!=-1){
if(w_pid==0)
continue;
printf("w_pid=%d\n",w_pid);
if(WIFEXITED(status))
printf("exit value=%d\n",WEXITSTATUS(status));
if(WIFSIGNALED(status))
printf("term signal=%d\n",WTERMSIG(status));
}
}
return 0;
}
[ [email protected] 1-pipe]$ ./test
root 840 0.0 0.0 115300 956 ? S 08:24 0:00 /bin/bash /usr/sbin/ksmtuned
gjw 2259 0.0 0.0 72384 780 ? Ss 08:25 0:00 /usr/bin/ssh-agent /bin/sh -c exec -l /bin/bash -c "env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic"
gjw 3189 0.0 0.0 116952 3616 pts/0 Ss 08:25 0:00 bash
gjw 4922 0.0 0.0 116820 3360 pts/1 Ss+ 08:52 0:00 bash
gjw 10706 0.0 0.0 116740 3252 pts/2 Ss 10:49 0:00 bash
gjw 16374 0.0 0.0 112728 988 pts/0 S+ 12:53 0:00 grep bash --color=auto
w_pid=16375
exit value=0
w_pid=16374
exit value=0