linux進程篇 (三) 進程間的通訊1 管道通訊

通訊方式分4大類:node


管道通訊:無名管道 有名管道
信號通訊:發送 接收 和 處理
IPC通訊:共享內存 消息隊列 信號燈
socke 網絡通訊網絡

用戶空間      進程A     <----沒法通訊---->      進程B
-----------------|--------------------------------------|--------------
                 |                                |
內核空間          |<------------->  對象 <--------------->|    

----------------------------------------------------------------------

//基於文件IO的思想
//open    打開或者建立一個文件,內核開闢一個buffer -->打開對象
//write    往buffer裏面寫
//read    從buffer讀
//close    釋放buffer

 

1. 進程間的管道通訊

用戶空間       進程A       <----沒法通訊---->       進程B
-----------------|--------------------------------------|--------------
              |                               |
內核空間        |<------------->  管道 <--------------->|    

----------------------------------------------------------------------

管道文件時一個特殊的文件,由隊列來實現
open --> pipe
管道中的東西讀完了,就刪除了、
管道中若是沒有東西可讀,就會 讀堵塞
管道中若是寫滿了,就會寫阻塞

 

1.1 無名管道

無名管道用於父子進程帶有親緣關係的進程spa

#include <unistd.h>
int pipe(int fildes[2]);    //建立
//文件描述符 filds[0]-read--出隊     filds[1]-write--入隊

write();    //
read();        //
close(fd[0]);
close(fd[1]);

------------------------------
fd[1]write            fd[0]read
------------------------------

小例子code

int main()
{
    int fd[2];    //pipe的2個文件描述符
    int ret;
    ret = pipe(fd);    //建立管道
    if(ret < 0){
        perror("pipe");
        return -1;
    }
    printf("fd[0] = %d, fd[1] = %d\n",fd[0],fd[1]);
    return 0;
}
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd[2];
    int ret;
    const char *writebuf = "hello pipe";
    char readbuf[1024] = {0};

    //1,建立pipe
    ret = pipe(fd);
    if(ret < 0)
    {
        perror("pipe");
        return -1;
    }
    printf("fd[0] = %d,fd[1] = %d\n",fd[0],fd[1]);

    //2.write
    ret = write(fd[1],writebuf,strlen(writebuf));
    if(ret < 0){
        perror("write");
    }
    //2.read
    ret = read(fd[0],readbuf,1024);
    if(ret < 0){
        perror("read");
        return -1;
    }

    printf("read: %s\n",readbuf);

    //3.close
    close(fd[0]);
    close(fd[1]);
    return 0;
}

 

1.2 有名管道

  對於無名管道,pipe要在fork以前建立,這樣fork的時候,會將fd[0]和fd[1]拷貝,這樣兩個進程就使用的是同2個設備描述符,若是pipe在fork以後建立,那個2個進程就會分別建立1個管道,操做的不是同一個管道文件,就沒辦法實行通訊。對象

   也就是說,無名管道只能用於fork建立這樣的父子進程, 若是無親緣關係的進程,無名管道沒辦法進行通訊,就只能使用有名管道。 blog

  有名管道 即建立一個帶有文件inode節點的管道文件 p, 該文件不佔有內存空間,僅有一個文件節點, 當該節點被open時,才佔用內存空間。隊列

   mkfifo 只是在用戶空間建立了一個管道文件,並不是在內存空間建立管道,只有在open時,纔在內存空間建立一個管道。進程

   注,有名管道兩端成對打開時纔會開始執行ip

#include <sys/types.h>
#include <sys/stat.h>

int mkfifo(const char *path, mode_t mode);    //文件路徑 文件權限

 

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    int ret;    //0=ok    -1=failes

    ret = mkfifo("./fifo",0755); //建立管道文件 路徑+權限
    if(ret < 0){
        perror("mkfifo");
        return -1;
    }
    return 0;
}

例子內存

fifo.c 建立有名管道文件

lude <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>

int main(int argc, char const *argv[])
{
    int ret;

    ret = mkfifo("./fifo",0755); //建立管道文件 路徑+權限
    if(ret < 0){
        perror("mkfifo");
        return -1;
    }
    return 0;
}

 

first.c 進程1

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd;
    int process_int = 0;

    fd = open("./fifo",O_WRONLY);    //注,有名管道兩端成對打開時纔會開始執行
    if(fd < 0){
        perror("open");
        return -1;
    }
    puts("fifo open success.");

    for(int i=0;i<5;i++){
        puts("我是第一個進程");
    }
    sleep(5);
    process_int = 1;

    write(fd,&process_int,1);
    while(1);
    return 0;
}

 

second.c 進程2

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc, char const *argv[])
{
    int fd;
    int process_int = 0;

    fd = open("./fifo",O_RDONLY);    //注,有名管道兩端成對打開時纔會開始執行
    if(fd < 0){
        perror("open");
        return -1;
    }
    puts("fifo open success.");
    
    read(fd,&process_int,1);
    while(process_int == 0);

    for(int i=0;i<5;i++){
        puts("我是第二個進程");
    }

    while(1);
    return 0;
}
相關文章
相關標籤/搜索