zoukankan      html  css  js  c++  java
  • Linux进程间通信 -- 管道(pipe)

    前言

       进程是一个独立的资源管理单元,不同进程间的资源是独立的,不能在一个进程中访问另一个进程的用户空间和内存空间。但是,进程不是孤立的,不同进程之间需要信息的交互和状态的传递,因此需要进程间数据的传递、同步和异步的机制。

        当然,这些机制不能由哪一个进程进行直接管理,只能由操作系统来完成其管理和维护,Linux提供了大量的进程间通信机制,包括同一个主机下的不同进程和网络主机间的进程通信,如下图所示:
    mark

    • 同主机间的信息交互
    • 无名管道
      特点:多用于亲缘关系进程间通信,方向为单向;为阻塞读写;通信进程双方退出后自动消失
      问题:多进程用同一管道通信容易造成交叉读写的问题
    • 有名管道
      FIFO(First In First Out),方向为单向(双向需两个FIFO),以磁盘文件的方式存在;通信双方一方不存在则阻塞
    • 消息队列
      可用于同主机任意多进程的通信,但其可存放的数据有限,应用于少量的数据传递
    • 共享内存
      可实现同主机任意进程间大量数据的通信,但多进程对共享内存的访问存在着竞争
    • 同主机进程间同步机制:信号量(Semaphore)
    • 同主机进程间异步机制:信号(Signal)
    • 网络主机间数据交互:Socket(套接字)

    1. 无名管道

    1). 概念

        无名管道是一类特殊的文件,在内核中对应着一段特殊的内存空间,内核在这段内存空间中以循环队列的方式存储数据;
       无名管道的内核资源在通信双方退出后自动消失,无需人为回收;
       无名管道主要用于连通亲缘进程(父子进程),用于双方的快捷通信,通信为单向通信

    2). 操作

    1. 创建

    pipe()

    • 头文件

          #include <unistd.h>
      
    • 函数原型

          int pipe(int pipedes[2])
      
    • 参数

    pipedes[2]:存储文件描述符
    mark

    • 返回值
      成功:0
      失败:-1

    2. 读写

    读进程 写进程 管道无数据 管道有数据
    阻塞√ 立刻返回0 返回数据
    阻塞√ 读阻塞 读数据并返回
    阻塞√ 收到SIGPIPE信号,write返回-1
    阻塞√ 写入 若满,阻塞等待

    3. 重定向
      所谓重定向,即关闭某个标准I/O设备(stdin(0), stdout(1), stderr(2)), 而将某一个普通的文件描述符设置为0/1/2.
      重定向,主要是采用 dup函数来实现的:

    • dup函数
      mark
    • 作用
      复制文件描述符

    • 头文件

          #include <unistd.h>
      
    • 函数原型

      函数 原型 描述
      dup int dup(int oldfd) 复制oldfd文件表项,并返回未用的最小值描述符
      dup2 int dup2(int oldfd, int newfd) 复制oldfd文件表项到newfd,newfd为用户自定义值,而后关闭oldfd
    • 参数

    oldfd:源文件的描述符(要求该文件描述符必须有效,文件必须处于打开状态)
    newfd:新的文件描述符,个人理解为oldfd的软链接

    • 返回值
      成功:最小值文件描述符(dup) / newfd的值(dup2)
      失败:-1

    2. 有名管道

    1). 概念

     又称FIFO(Fisrt In First out), 是磁盘上的一个特殊文件,没有在磁盘存储真正的信息,其所存储的信息在内存中
     通信双方进程结束后,自动丢弃FIFO中的信息,但其在磁盘的文件路径本身依然存在

    2). 操作

    1. 创建 - mkfifo()

    • 头文件

          #include <sys/stat.h>
      
    • 函数原型

          int mkfifo(const char *pathname, mode_t mode)
      
    • 参数

    pathname: FIFO文件
    mode: 创建文件的属性(权限)

    • 返回值
      成功:0
      失败:-1

    2. 读写

    读进程 写进程 FIFO无数据 FIFO有数据
    阻塞 阻塞
    阻塞 阻塞
    写入 读出(未满,读写同时)
    √x 即写中途退出,读直接返回0 same
    √x 读中途退出,写返回SIGPIPE same

    3. 补充

    access函数

    • 作用
      检查用户(进程)对文件的权限

    • 头文件

          #include <unistd.h>
      
    • 函数原型

          int access(const char *pathname, int mode)
      
    • 参数

    pathname: 即文件名
    mode:测试的属性

    mode description
    F_OK 该文件是否存在
    R_OK 可读
    W_OK 可写
    X_OK 可执行
    bitwise 属性(读/写/执行等)
    • 返回值
      成功:0
      失败:-1

    4. 代码示例

    1). PIPE

    /*
     * Filename: pipe.c
     */
     
    #include <stdio.h>
    #include <unistd.h>     //for pipe()
    #include <string.h>     //for memset()
    #include <stdlib.h>     //for exit()
    
    int main()
    {
        int fd[2];
        char buf[20];
        if(-1 == pipe(fd))
        {
            perror("pipe");
            exit(EXIT_FAILURE);
        }
    
        write(fd[1], "hello,world", 12);
        memset(buf, '', sizeof(buf));
    
        read(fd[0], buf, 12);
        printf("The message is: %s
    ", buf);
    
        return 0;
    }
    
    

    2). FIFO

    程序的步骤:

    1. 创建一个新的fifo文件
    2. fifo_snd.c文件负责向fifo中写入数据
    3. fifo_rcv.c负责从fifo中读取数据并打印

    1. fifo_snd.c:

    /*
     *File: fifo_send.c
     */
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/ipc.h>
    #include <fcntl.h>
    
    
    #define FIFO "/tmp/my_fifo"
    
    int main()
    {
        char buf[] = "hello,world";
    
        //`. check the fifo file existed or not
        int ret;
        ret = access(FIFO, F_OK);
        if(ret == 0)    //file /tmp/my_fifo existed
        {
            system("rm -rf /tmp/my_fifo");
        }
    
        //2. creat a fifo file
        if(-1 == mkfifo(FIFO, 0766))
        {
            perror("mkfifo");
            exit(EXIT_FAILURE);
        }
    
        //3.Open the fifo file
        int fifo_fd;
        fifo_fd = open(FIFO, O_WRONLY);
        if(-1 == fifo_fd)
        {
            perror("open");
            exit(EXIT_FAILURE);
    
        }
    
        //4. write the fifo file
        int num = 0;
        num = write(fifo_fd, buf, sizeof(buf));
        if(num < sizeof(buf))
        {
            perror("write");
            exit(EXIT_FAILURE);
        }
    
        printf("write the message ok!
    ");
    
        close(fifo_fd);
    
        return 0;
    }
    
    

    2. fifo_rcv.c:

    /*
     *File: fifo_rcv.c
     */
     
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/stat.h>
    #include <sys/ipc.h>
    #include <fcntl.h>
    
    
    #define FIFO "/tmp/my_fifo"
    
    int main()
    {
        char buf[20] ;
        memset(buf, '', sizeof(buf));
    
        //`. check the fifo file existed or not
        int ret;
        ret = access(FIFO, F_OK);
        if(ret != 0)    //file /tmp/my_fifo existed
        {
            fprintf(stderr, "FIFO %s does not existed", FIFO);
            exit(EXIT_FAILURE);
        }
    
        //2.Open the fifo file
        int fifo_fd;
        fifo_fd = open(FIFO, O_RDONLY);
        if(-1 == fifo_fd)
        {
            perror("open");
            exit(EXIT_FAILURE);
    
        }
    
        //4. read the fifo file
        int num = 0;
        num = read(fifo_fd, buf, sizeof(buf));
    
        printf("Read %d words: %s
    ", num, buf);
    
        close(fifo_fd);
    
        return 0;
    }
    
    
  • 相关阅读:
    zookeeper基础笔记
    基于spring@aspect注解的aop实现
    Struts2中的开启AsyncContext的方法
    在执行gem install redis时 : ERROR: Error installing redis: redis requires Ruby version >= 2.2.2
    ConcurrentHashMap原理笔记
    Java并发Condition原理分析
    CountDownLatch实现原理
    ThreadPoolExecutor 线程池原理分析
    HashMap原理
    线程池的用法
  • 原文地址:https://www.cnblogs.com/Jimmy1988/p/7553069.html
Copyright © 2011-2022 走看看