管道通信
匿名管道
創建匿名管道
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(匿名管道)之間唯一的區別在它們創建與打開的⽅方式不同,一但這些工作完成之后,它們具有相同的語義。
精選文章都同步在公眾號里面,公眾號看起會更方便,隨時隨地想看就看。微信搜索 龍躍十二 或者掃碼即可訂閱。