利用管道實現進程間通信

管道通信

匿名管道

創建匿名管道

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(匿名管道)之間唯一的區別在它們創建與打開的⽅方式不同,一但這些工作完成之後,它們具有相同的語義。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章