目录

二、管道(PIPE 、FIFO)

2.1无名管道(PIPE)

2.1.1 父子通信

2.1.2 兄弟通信

2.2有名管道(FIFO)


二、管道(PIPE 、FIFO)

最古老的IPC之一, 管道文件作为媒介进行传输

其中分为有名管道无名管道

无名管道的管道文件在文件系统中不可见, 而有名可见

管道通信实质上是内存通信, 由内核负责

 

2.1无名管道(PIPE)

只能用于亲缘关系的进程(父子 、 兄弟), 由它的机制决定

无名管道的管道文件在文件系统中不可见

使用方法:

1、父进程调用pipe() 函数创建无名管道, 无名管道有读端 、 写端

2、用fork产生子进程, 子进程自动继承父进程的描述符  ,也就是 无名管道的 读端 、 写端

3、这是一种半双工通信, 一条管不能同时又进又出,想 读,就把写关了,另一边就把写关了,读就开 , 如下图所示

 

2.1.1 父子通信

首先父进程创建一个无名管道 , 有读、写描述符

然后fork 后产生一个子进程,它和父进程称为父子进程

这个子进程继承了父进程的读、写描述符

下面代码,子进程是写,所以要关掉读 ; 父进程是读,所以要关掉写

代码如下(pipe、父子进程):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    //读、写 描述符
    //pipefd[0] 读端描述符,从管道文件读
    //pipefd[1] 写端描述符,往管道文件写
    int pipefd[2];


    //创建无名管道
    int res = pipe(pipefd);
    if(res==-1){
        perror("pipe");
        exit(-1);
    }

    //创建子进程
    if(!fork()){//子
        //写的时候,要关闭读端
        close(pipefd[0]);

        int i = 0;
        for(i=0;i<50;i++){
            write(pipefd[1],&i,sizeof(i));//往管道文件里写
            //write 函数参数 介绍
            //第一个参数:写描述符
            //第二个参数:数据的地址
            //第三个参数:数据的大小 (字节)
            usleep(100000);
        }
   
        close(pipefd[1]); //退出之前,顺便关了写描述符
        exit(0);
    }

    //父进程
    printf("pid = %d\n",getpid());
    char buf[10] = {};
    int num = 0;//和子进程发送的数据类型保持一致

    //读的时候,要关闭写端
    close(pipefd[1]);

    while(1){
        res = read(pipefd[0],&num,sizeof(num));//从管道文件读
        //read 函数参数 介绍
        //第一个参数:读描述符
        //第二个参数:数据的地址
        //第三个参数:数据的大小 (字节)
        if(res<=0)
            break;
        printf("%d\n",num);
    }

    close(pipefd[0]);//退出之前,顺便关了读描述符
    wait(NULL);//等待子进程退出,回收它的资源(我的系统编程第二篇有讲过)
    return 0;
}

2.1.2 兄弟通信

父进程创建了 读、写 描述符

fork 两次后产生了两个子进程(互为兄弟进程),它们都继承父进程的 读、写 描述符

在这里,父进程不参与通信,因此父进程的读、写描述符都需要关闭掉

下面的代码,子1是写,所以关掉读 ; 子2是读,所以关掉写

代码如下(pipe、兄弟进程):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
    int pipefd[2];

    //创建无名管道
    int res = pipe(pipefd);
    if(res==-1){
        perror("pipe");
        exit(-1);
    }

    //创建子进程
    if(!fork()){//子1
        //写,关闭读端
        close(pipefd[0]);

        int i = 0;
        for(i=0;i<50;i++){
            write(pipefd[1],&i,sizeof(i));
            usleep(100000);
        }
        
        close(pipefd[1]);
        exit(0);
    }

    if(!fork()){//子2
        char buf[10] = {};
        int num = 0;
        //读,关闭写端
        close(pipefd[1]);

        while(1){
            res = read(pipefd[0],&num,sizeof(num));
            if(res<=0)
                break;
            printf("%d\n",num);
        }

        close(pipefd[0]);

        exit(0);
    }

    //父进程
    printf("pid = %d\n",getpid());
 
    //父进程不通信,关闭读端和写端
    close(pipefd[0]);
    close(pipefd[1]);

    wait(NULL);
    wait(NULL);
    return 0;
}

 

 

2.2有名管道(FIFO)

用于所有进程的通信,不局限父子、兄弟进程

有名管道在文件系统中是可见,虽然可见, 但是是在内存当中

使用方法: 

1、进程1创建一个有名管道文件,可以在文件系统中看到, 然后和它通信的进程2打开这个文件即可通信

2、没有读、写描述符, 这里只有文件描述符,用它进行读或写

3、这里也是一个半双工通信

 

 

例如进程1创建管道文件、然后打开文件获取文件描述符、接着进行用描述符来读管道文件

代码如下(fifo、读):

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
    char buf[100] = {};

    //1.创建管道文件
    int res = mkfifo("/home/zzy/a.fifo",0666);
    if(res==-1){
        perror("mkfifo");
        exit(-1);
    }

    //打开管道文件 读
    int fd = open("/home/zzy/a.fifo",O_RDONLY);
    if(fd==-1){
        perror("open");
        exit(-1);
    }

    //读管道
    while(1){
        res = read(fd,buf,sizeof(buf));
        if(res<=0)
            break;
        printf("buf = %s\n",buf);
    }

    close(fd);

    return 0;
}

 

而进程2不需要创建管道文件, 打开进程1创建的并获取文件描述符、接着进行用描述符来写管道文件

代码如下(fifo、写):

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

int main()
{
    char buf[100] = {};

    //打开管道文件 写
    int fd = open("/home/zzy/a.fifo",O_WRONLY); //有名管道在文件系统中可见
    if(fd==-1){
        perror("open");
        exit(-1);
    }

    //写管道
    while(1){
        printf("请输入:");
        fgets(buf,sizeof(buf),stdin);
        write(fd,buf,sizeof(buf));
    }

    close(fd);

    return 0;
}

Logo

更多推荐