利用管道實現進程間通信


管道通信

匿名管道

創建匿名管道

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(匿名管道)之間唯一的區別在它們創建與打開的⽅方式不同,一但這些工作完成之后,它們具有相同的語義。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM