利用管道實現進程間通信
阿新 • • 發佈:2018-05-01
Linux 進程 管道 通信 管道通信
匿名管道
創建匿名管道
int pipe(int pipefd[2]);
pipefd[0] : 表示讀管道
pipefd[1] : 表示寫管道
返回 0表示成功,非零表示創建失敗。
代碼事例
:
//匿名管道 int main() { int fds[2]; int len; char buf[100]={}; if(pipe(fds)==-1) //創建管道 perror("pipe"),exit(1); while(fgets(buf,100,stdin)) { len = strlen(buf); if(write(fds[1],buf,len)==-1) //把內容寫進管道 perror("write"),exit(1); memset(buf,0x00,sizeof(char)*100); if(read(fds[0],buf,len)==-1) //從管道裏面讀取內容到數組中 perror("read"),exit(1); if(write(1,buf,len)==-1) //把從管道裏讀出的內容寫到標準輸出 perror("write"),exit(1); } return 0; }
結果展示
:
日常運用事例
: who | wc -l
這樣的事例我們經常用到,用管道連接命令會令你得心應手。
圖片解析
:
####利用管道進行父子進程通信
.
: 圖片解析原理
代碼示例:
//父子進程通信 int main() { char buf[1024]="change world!\n"; int fds[2]; if(pipe(fds)==-1) perror("pipe"),exit(1); pid_t pid = fork(); //創建匿名管道 if(pid==0) { close(fds[0]); //關閉管道讀描述符 if(write(fds[1],buf,1024)==-1) //寫進管道 perror("write"),exit(1); close(fds[1]); exit(1); } else { memset(buf,0x00,1024); close(fds[1]); //關閉管道寫描述符 if(read(fds[0],buf,1024)==-1) //從管道讀內容 perror("read"),exit(1); if(write(1,buf,1024)==-1) perror("write"),exit(1); close(fds[0]); exit(1); } return 0; }
結果
詳細過程圖解
####管道讀寫規則
當沒有數據可讀時
- O_NONBLOCK disable:read調用阻塞,即進程暫停執行,.一直等到有數據來到為止。
- O_NONBLOCK enable:read調用返回-1,errno值為EAGAIN。
當管道滿的時候
- O_NONBLOCK disable: write調用阻塞,直到有進程讀.走數據
- O_NONBLOCK enable:調用返回-1,errno值為EAGAIN
- 如果所有管道寫端對應的文件描述符被關閉,則read返回0
- 如果所有管道讀端對應的文件描述符被關閉,則write操作會產生信號SIGPIPE,進而可能導致write進程退出
- 當要寫.入的數據量不.大於PIPE_BUF時,linux將保證寫.入的原.子性。
- 當要寫.入的數據量.大於PIPE_BUF時,linux將不再保證寫.入的原.子性。
管道特點
: - 只能?用於具有共同祖先的進程(具有親緣關系的進程)之間進?行通信;通常,一個管道由一個進程創建,然後該進程調?用fork,此後?父、?子進程之間就可應?用該管道。
- 管道提供流式服務
- 一般?而?言,進程退出,管道釋放,所以管道的?生命周期隨進程
- 一般?而?言,內核會對管道操作進?行同步與互斥管道是半雙?工的,數據只能向?一個?方向流動;需要雙?方通信時,需要建?立起兩個管道
命名管道
我們剛剛可以用匿名管道在父子進程之間通信,那如果是兩個不想光的進程之間該如何通信呢?
創建命名管道
.
: 在命令行可以直接創建mkfifo filename
: 也可以在程序內部創建,相關函數int mkfifo(const char *pathname, mode_t mode);
代碼示例:
:
int main()
{
mkfifo("my.p",0644);
return 0;
}
####無關進程之間通信代碼示例
。
: 從標準輸入讀入內容進管道
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
mkfifo("my.p",0664);
int outfd = open("my.p",O_WRONLY);
if(outfd==-1)
perror("open my.txt"),exit(1);
char buf[1024]={};
int n = 0;
while(fgets(buf,1024,stdin))
{
write(outfd,buf,1024);
memset(buf,0x00,1024);
}
close(outfd);
從管道中讀內容,標準輸出輸出
#include<string.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int infd = open("my.p",O_RDONLY);
if(infd==-1)
perror("open my.p"),exit(1);
char buf[1024]={};
int n = 0;
while((n = read(infd,buf,1024))>0)
{
write(1,buf,n);
memset(buf,0x00,1024);
}
close(infd);
unlink("my.p"); //刪除管道
return 0;
}
運行結果:
這裏就利用管道實現了兩個無關進程之間的通信。
###匿名管道和命名管道的區別。
- 匿名管道由pipe函數創建並打開。
- 命名管道由mkfifo函數創建,打開?用open
- FIFO(命名管道)與pipe(匿名管道)之間唯一的區別在它們創建與打開的?方式不同,一但這些工作完成之後,它們具有相同的語義。
利用管道實現進程間通信