Linux进程间通信—管道

左手的ㄟ右手 2023-02-12 10:24 80阅读 0赞

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

目录

        • 关于管道
        • 父子进程间的管道通信
        • 函数 popen 和 pclose
        • FIFO 命名管道

关于管道

管道是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 程序如下:

  1. #define BUFSIZE 512
  2. static void PipeDemo()
  3. {
  4. int fd[2];
  5. pid_t pid;
  6. char buf[BUFSIZE] = {
  7. 0};
  8. int readsize = 0;
  9. if(pipe(fd) < 0) {
  10. printf("pipe failed!\n");
  11. return;
  12. }
  13. if((pid = fork()) < 0) {
  14. printf("fork failed!\n");
  15. return;
  16. }
  17. else if(pid == 0) {
  18. close(fd[0]);
  19. printf("Child Process Say Hello to Father Process\n");
  20. write(fd[1], "Hello Father\n", 13);
  21. }
  22. else {
  23. close(fd[1]);
  24. readsize = read(fd[0], buf, BUFSIZE);
  25. if(strcmp(buf, "Hello Father\n") == 0) {
  26. printf("OK, Good Boy\n");
  27. }
  28. }
  29. exit(0);
  30. }

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

函数 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 命令,并打印结果:

  1. static void PopenDemo()
  2. {
  3. FILE *fd = NULL;
  4. char buf[BUFSIZE] = {
  5. 0};
  6. size_t n = 0;
  7. fd = popen("ls -l", "r");
  8. n = fread(buf, BUFSIZE, 1, fd);
  9. printf("%s", buf);
  10. if(pclose(fd) == -1) {
  11. printf("pclose failed.");
  12. }
  13. }

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

FIFO 命名管道

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

  1. // fifo.c create 2020/5/26
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <sys/types.h>
  5. #include <sys/stat.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <stdlib.h>
  9. static void ModifyFIFO()
  10. {
  11. const char *fifofile = "/tmp/fifo";
  12. if(access(fifofile, F_OK) != 0) {
  13. if(mkfifo(fifofile, 0755) != 0) {
  14. printf("mkfifo failed.");
  15. exit(0);
  16. }
  17. }
  18. int fd = open(fifofile, O_RDWR);
  19. if(fd < 0) {
  20. printf("open fifo failed.");
  21. exit(0);
  22. }
  23. char buf[512] = {
  24. 0};
  25. int size = 0;
  26. while(1) {
  27. memset(buf, 0, 512);
  28. size = read(fd, buf, 512);
  29. if(size > 0) {
  30. printf("%s\n", buf);
  31. }
  32. if(strstr(buf, "exit")) {
  33. break;
  34. }
  35. else if(strstr(buf, "Hello Dad")) {
  36. write(fd, "OK, Good boy~", 13);
  37. }
  38. }
  39. }
  40. int main()
  41. {
  42. ModifyFIFO();
  43. return 0;
  44. }

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

发表评论

表情:
评论列表 (有 0 条评论,80人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Linux进程通信管道

    管道用于进程间的通信,进程间通信的 公共资源叫做临界资源,访问临界资源的代码叫做临界区 。 管道文件以p开头,管道是一种最基本的IPC机制 管道又有匿名管道和命名管道之分