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;
}

不同進程之間執行效果如下:
多進程通信

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章