zoukankan      html  css  js  c++  java
  • linux多进/线程编程(4)——进程间通信之pipe和fifo

     

    前言:

    Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。

    常用的进程间通信方式有:

    ① 管道 (使用最简单)

    ② 信号 (开销最小)

    ③ 共享映射区 (无血缘关系)

    ④ 本地套接字 (最稳定) https://zhuanlan.zhihu.com/p/336734605

    本文主要讲解pipe管道的用法和代码示例。

    管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe系统函数即可创建一个管道。有如下特质:
      1. 其本质是一个伪文件(实为内核缓冲区) 
      2. 由两个文件描述符引用,一个表示读端,一个表示写端。
      3. 规定数据从管道的写端流入管道,从读端流出。
    管道的原理: 管道实为内核使用环形队列机制,借助内核缓冲区(4k)实现。

    管道的局限性:

    1. 数据一旦被读走,便不在管道中存在,不可反复读取。
    2. 由于管道采用半双工通信方式。因此,数据只能在一个方向上流动。
    3. 只能在有公共祖先的进程间使用管道。

    pipe

    NAME
           pipe, pipe2 - create pipe
    
    SYNOPSIS
           #include <unistd.h>
    
           int pipe(int pipefd[2]);
    
           #define _GNU_SOURCE             /* See feature_test_macros(7) */
           #include <fcntl.h>              /* Obtain O_* constant definitions */
           #include <unistd.h>
    
           int pipe2(int pipefd[2], int flags);

     利用pipe实现ps aux | grep bash

    int pipe_fd[2];
      pipe(pipe_fd);
    
      pid_t pid = fork();
    
      if (pid == 0) {
        //son  -----> 这里会产生僵尸进程
        //管道的使用规范:关闭读端
        close(pipe_fd[0]);
        //1.先重定向
        dup2(pipe_fd[1], STDOUT_FILENO);//标准输出重定向到管道写端
        //2.execlp
        execlp("ps", "ps", "aux", nullptr);
      } else if (pid > 0) {
        //parent
        //管道的使用规范:关闭写端
        close(pipe_fd[1]);
        //1.先重定向
        dup2(pipe_fd[0], STDIN_FILENO);//标准输入重定向到管道读端
        //2.execlp   -----> grep 会阻塞
        execlp("grep", "grep", "--color=auto", "bash", nullptr);
        //代码的问题:父进程认为还有写端存在,就有可能还有人给发数据,继续等待
        //管道的使用规范
      }

    fifo 可以实现无血缘关系的进程间通信

    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    
    
    int main(int argc, char * argv[]) {
      if (argc != 2) {
        printf("./a.out fifonname
    ");
        return -1;
      }
      //当前目录有一个myfifo文件 
      //打开fifo文件
      int fd = open(argv[1], O_WRONLY);
      //
      char buf[256];
      int num = 1;
      while(1) {
        memset(buf, 0x00, sizeof(buf));
        //循环写
        sprintf(buf, "xiaoming%04d", num++);
        write(fd, buf, strlen(buf));
        sleep(1);
      }
    
      //关闭描述符
      closde(fd);
    
      return 0;
    }
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <string.h>
    
    
    int main(int argc, char * argv[]) {
      if (argc != 2) {
        printf("./a.out fifonname
    ");
        return -1;
      }
      //当前目录有一个myfifo文件 
      //打开fifo文件
      int fd = open(argv[1], O_RDONLY);
    
      char buf[256];
      int ret = 0;
      while(1) {
        //循环读
        ret = read(fd, buf, sizeof(buf));
        if (ret > 0) {
          printf("read:%s
    ", buf);
        }
      }
    
      //关闭描述符
      closde(fd);
    
      return 0;
    }
  • 相关阅读:
    Go jaegerde 应用【logger+gorm+grpc+http】
    Go gRPC 调试工具
    iris和xxl-job整合
    Go Grpc部署到 k8s【端口共享】
    rocketmq事务 go 采用rocketmq-client-go的实现
    Go Grpc部署到 k8s【负载均衡】
    ubuntu18安装Kubernetes 1.20.5
    k8s Python API
    go nacos服务发现
    k8s集群日志收集ELK和graylog
  • 原文地址:https://www.cnblogs.com/kongweisi/p/14629046.html
Copyright © 2011-2022 走看看