Linux 进程间通信(1) -- 管道

作者: wulegekong | 来源:发表于2017-02-07 18:53 被阅读0次

    进程间通信(IPC - InterProcess Communication)

    通信的方式有很多: 文件, 管道, 信号, 共享内存, 消息队列, 套接字, 命名管道等等;

    • 但是由于设计缺陷现在常用的有:
      1.管道(简单, 默认匿名管道, 还有有名管道)
      2.信号(开销小, 但是如果不是做系统编程一般不用, 因为缺点大于有点, 比如有没有收到无法确认)
      3.共享映射区(无血缘关系之间)
      4.本地套接字(最稳定)

    一、 管道(匿名, pipe)

    1. 介绍:
      本质是内核缓冲区
      特点: 两端, 对应读和写; 是一个伪文件, 进程结束, 缓冲区消失
      原理: 环形队列实现(取余的算法...)
      管道尺寸默认大小 4k (ulimit -a 查看pipe size; 或者函数: long fpathconf(int fd, int name);)
      局限: 不能多次访问, 匿名管道只能是有血缘关系的进程间通信(fifo有名管道可以实现无血缘关系间通信)
    2. 创建 int pipe(int fildes[2]);
    #include <stdio.h>
    #include <unistd.h>
    int main(int argc, const char* argv[]) {
        int fd[2];
        int ret = pipe(fd);
        if(ret == -1) {
            perror("pipe error");
            exit(1);
        }
        printf("fd[0] = %d\n", fd[0]);
        printf("fd[1] = %d\n", fd[1]);
        return 0;
    }
    
    1. 父子进程通信(使用匿名管道)
    #include <stdio.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    int main(int argc, const char* argv[]) {
        // 1. 创建管道
        int fd[2];
        int ret = pipe(fd);
        if(ret == -1) {
            perror("pipe error");
            exit(1);
        }
    
        // 2. 创建子进程
        pid_t pid = fork();
        if(pid == -1) {
            perror("fork error");
            exit(1);
        }
        // 3. 通信
        // 父进程 写操作
        if(pid > 0) {
            // parent process
            // 关闭读端
            close(fd[0]);
            char* p = "你是子进程吗?";
            sleep(2); //父进程写, 但是先sleep2秒, 此时子进程会等父进程写进去之后再读, 因为read函数是阻塞函数, 但是这是管道的阻塞属性
            //将其设置成非阻塞,  使用fcntl 函数
            write(fd[1], p, strlen(p)+1);
            close(fd[1]);
            wait(NULL);
        } else if(pid == 0) { // 子进程 读操作
            // 关闭写端
            close(fd[1]);
            char buf[512];
            int len = read(fd[0], buf, sizeof(buf));
            printf("%s, %d\n", buf, len);
            close(fd[0]);
        }
        return 0;
    }
    
    1. 管道的读写行为
    • 读操作:
      管道中有数据: read正常运行, 返回读取到的字节数
      管道中无数据: 1. 写端关闭, 相当于文件读取到了文件尾部, read返回0; 2.写端没有关闭, read阻塞
    • 写操作:
      管道读端关闭: 异常情况, 管道破裂, 异常退出, 通过13号信号(SIGPIPE)
      管道读端没有关闭: 1. 缓冲区没有满, 正常写; 2. 缓冲区已满, 写阻塞

    补充:

    当实现父子间进程通信时, 如果需要将终端(/dev/tty--)上输出的数据, 或者其他地方的数据写进管道时, 需要将终端对应的标准输出文件描述符重定向到写端, 使用函数: int dup2(int fildes, int fildes2);

    相关文章

      网友评论

        本文标题:Linux 进程间通信(1) -- 管道

        本文链接:https://www.haomeiwen.com/subject/qhcmittx.html