利用管道實現進程間通訊

管道通訊

匿名管道

建立匿名管道

int pipe(int pipefd[2]); pipefd[0] : 表示讀管道 pipefd[1] : 表示寫管道 返回 0表示成功,非零表示建立失敗。linux

代碼事例數組

//匿名管道                                                                                                                            
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 這樣的事例咱們常常用到,用管道鏈接命令會令你駕輕就熟。函數

圖片解析spa

這裏寫圖片描述

####利用管道進行父子進程通訊命令行

圖片解析原理 這裏寫圖片描述 代碼示例:3d

//父子進程通訊
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;
}

結果 這裏寫圖片描述 詳細過程圖解 這裏寫圖片描述code

####管道讀寫規則blog

當沒有數據可讀時生命週期

  • 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(匿名管道)之間惟一的區別在它們建立與打開的⽅方式不一樣,一但這些工做完成以後,它們具備相同的語義。

精選文章都同步在公衆號裏面,公衆號看起會更方便,隨時隨地想看就看。微信搜索 龍躍十二 或者掃碼便可訂閱。

<p align="center"><image src="https://tva1.sinaimg.cn/large/006tNbRwly1galsp9a07kj30p00dwae3.jpg" ></image></p>

相關文章
相關標籤/搜索