Linux进程间通信—管道

前言:本篇主要总结介绍了Linux进程间通信方式之一管道技术。包括管道(无名有名)的基本概念、相关API的介绍、及Demo代码示例。

关于管道

管道是UNIX系统最古老的一种 IPC 方式,所有UNIX系统都提供这种通信机制。

管道 接口 特性
无名管道 pipe 半双工为主、父子进程间通信
命名管道 FIFO mkfifo 和 mkfifoat 多个不相关进程间通信
  • int pipe(int pipefd[2])
    该函数经由参数 pipefd 返回两个文件描述符:pipefd[0] 为读打开,pipefd[1] 为写打开。pipefd[1] 的输出是 pipefd[0] 的输入
  • int mkfifo(const char *pathname, mode_t mode)
  • int mkfifoat(int dirfd, const char *pathname, mode_t mode)
    使用 mkfifo 和 mkfifoat 两个接口来创建 FIFO 文件,其中参数 mode 与 open 函数中的 mode 相同;
    mkfifoat 与 mkfifo 相似,其中 fd 用来在 fd 文件描述符表示的目录相关的位置创建一个 FIFO。

父子进程间的管道通信

一般,进程先调用 pipe,再调 fork,从而创建从父进程到子进程的 IPC 管道,如图所示:
父子进程间的管道
下面来创建一个父子进程间的通信管道,子进程通过该管道像父进程传送数据,父进程使用该数据。Demo 程序如下:

#define BUFSIZE 512
static void PipeDemo()
{
    int fd[2];
    pid_t pid;
    char buf[BUFSIZE] = {0};
    int readsize = 0;
    if(pipe(fd) < 0) {
        printf("pipe failed!\n");
        return;
    }
    if((pid = fork()) < 0) {
        printf("fork failed!\n");
        return;
    }
    else if(pid == 0) {
        close(fd[0]);
        printf("Child Process Say Hello to Father Process\n");
        write(fd[1], "Hello Father\n", 13);
    }
    else {
        close(fd[1]);
        readsize = read(fd[0], buf, BUFSIZE);
        if(strcmp(buf, "Hello Father\n") == 0) {
            printf("OK, Good Boy\n");
        }
    }
    exit(0);
}

该程序测试执行后打印如下:
在这里插入图片描述

函数 popen 和 pclose

  • FILE *popen(const char *command, const char *type)
    函数 popen 先执行 fork,然后调用 exec 执行 command,并且返回一个标准 I/O 文件指针。
    如果 type 是 “r”,则文件指针链接到 command 的标准输出;
    如果 type 是 “w”,则文件指针链接到 command 的标准输入;
  • int pclose(FILE *stream)
    on success, returns the exit status of the command; if wait4(2) returns an error, or some other error is detected, -1 is returned.

下面使用 popen 执行一个 ls 命令,并打印结果:

static void PopenDemo()
{
    FILE *fd = NULL;
    char buf[BUFSIZE] = {0};
    size_t n = 0;
    fd = popen("ls -l", "r");
    n = fread(buf, BUFSIZE, 1, fd);
    printf("%s", buf);
    if(pclose(fd) == -1) {
        printf("pclose failed.");
    }
}

执行结果如下:
popen执行结果

FIFO 命名管道

FIFO 是一种文件类型,通过FIFO,不相干的进程之间也能交换数据。
下面就使用 mkfifo 函数来创建一个 FIFO 文件,并用与不同进程间通信。
该Demo程序通过 fifo 接收其他进程的消息,并作出回应

// fifo.c create 2020/5/26
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
static void ModifyFIFO()
{
    const char *fifofile = "/tmp/fifo";
    if(access(fifofile, F_OK) != 0) {
        if(mkfifo(fifofile, 0755) != 0) {
            printf("mkfifo failed.");
            exit(0);
        }
    }
    int fd = open(fifofile, O_RDWR);
    if(fd < 0) {
        printf("open fifo failed.");
        exit(0);
    }
    char buf[512] = {0};
    int size = 0;
    while(1) {
        memset(buf, 0, 512);
        size = read(fd, buf, 512);
        if(size > 0) {
            printf("%s\n", buf);
        }
        if(strstr(buf, "exit")) {
            break;
        }
        else if(strstr(buf, "Hello Dad")) {
            write(fd, "OK, Good boy~", 13);
        }
    }
}
int main()
{
    ModifyFIFO();
    return 0;
}

不同进程之间执行效果如下:
多进程通信

posted @ 2020-05-26 18:52  Caso_卡索  阅读(100)  评论(0编辑  收藏  举报