• linux进程篇 (三) 进程间的通信1 管道通信


    通信方式分4大类:


    管道通信:无名管道 有名管道
    信号通信:发送 接收 和 处理
    IPC通信:共享内存 消息队列 信号灯
    socke 网络通信

    用户空间      进程A     <----无法通信---->      进程B
    -----------------|--------------------------------------|--------------
                     |                                |
    内核空间          |<------------->  对象 <--------------->|    
    
    ----------------------------------------------------------------------
    
    //基于文件IO的思想
    //open    打开或者创建一个文件,内核开辟一个buffer -->打开对象
    //write    往buffer里面写
    //read    从buffer读
    //close    释放buffer

    1. 进程间的管道通信

    用户空间       进程A       <----无法通信---->       进程B
    -----------------|--------------------------------------|--------------
                  |                               |
    内核空间        |<------------->  管道 <--------------->|    
    
    ----------------------------------------------------------------------
    
    管道文件时一个特殊的文件,由队列来实现
    open --> pipe
    管道中的东西读完了,就删除了、
    管道中如果没有东西可读,就会 读堵塞
    管道中如果写满了,就会写阻塞

    1.1 无名管道

    无名管道用于父子进程带有亲缘关系的进程

    #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
    ------------------------------

    小例子

    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
    ",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
    ",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
    ",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创建这样的父子进程, 如果无亲缘关系的进程,无名管道没办法进行通信,就只能使用有名管道。

      有名管道 即创建一个带有文件inode节点的管道文件 p, 该文件不占有内存空间,仅有一个文件节点, 当该节点被open时,才占用内存空间。

       mkfifo 只是在用户空间创建了一个管道文件,并非在内存空间创建管道,只有在open时,才在内存空间创建一个管道。

       注,有名管道两端成对打开时才会开始执行

    #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;
    }
  • 相关阅读:
    python3.5: error while loading shared libraries: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory
    php回溯
    PHPredis长连接pconnect
    php操作redis出现不报错就退出
    MSMQ消息队列
    消息队列使用的四种场景介绍(准载)
    Spring MVC参数封装传递
    Spring MVC配置实例
    .NET项目中使用PostSharp
    C#进阶系列——AOP
  • 原文地址:https://www.cnblogs.com/kmist/p/10635823.html
Copyright © 2020-2023  润新知