翼度科技»论坛 云主机 LINUX 查看内容

Linux进程通信 | 管道与FIFO

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
Linux进程间通信通常使用的方式有很多种,其中比较常用的包括管道(pipe)和 FIFO(命名管道)。本文将介绍这两种通信方式的基本概念,并用C语言编写示例代码,来说明如何在两个进程之间使用这些IPC机制进行通信。
管道(pipe)

管道是一种半双工的通信方式,用于父进程和子进程之间的通信。在 Linux 中,管道是一种特殊的文件,有两个端点,一个读端和一个写端。管道的基本操作包括创建管道、关闭文件描述符、读取数据和写入数据等。
创建管道

在 Linux 中,我们可以使用 pipe() 系统调用来创建管道。pipe() 函数的原型如下:
  1. #include <unistd.h>
  2. int pipe(int pipefd[2]);
复制代码
其中,pipefd 是一个数组,用于存储管道的读端和写端的文件描述符。pipe() 函数成功时返回 0,失败时返回 -1。
下面是一个创建管道的示例代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. int main()
  5. {
  6.     int pipefd[2];
  7.    
  8.     // 创建管道
  9.     if (pipe(pipefd) == -1) {
  10.         perror("pipe");
  11.         exit(EXIT_FAILURE);
  12.     }
  13.    
  14.     printf("读端文件描述符:%d\n", pipefd[0]);
  15.     printf("写端文件描述符:%d\n", pipefd[1]);
  16.    
  17.     exit(EXIT_SUCCESS);
  18. }
复制代码

  • 编译并运行,打印如下
  1. 读端文件描述符:3
  2. 写端文件描述符:4
复制代码
管道的读写

在使用管道进行通信时,父进程和子进程可以通过管道进行数据的读取和写入。在 C 语言中,我们可以使用 read()函数和 write() 函数来读取和写入数据。read() 函数用于从管道中读取数据,write() 函数用于向管道中写入数据,使用 close() 函数关闭文件描述符。在管道的使用中,我们应该在不需要的时候关闭管道的读端和写端,以避免资源浪费。
这三个函数的原型分别如下:
  1. #include <unistd.h>
  2. ssize_t read(int fd, void *buf, size_t count);
  3. ssize_t write(int fd, const void *buf, size_t count);
  4. int close(int fd);
复制代码
下面是一个父进程向子进程写入数据并读取返回结果的示例代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/wait.h>
  6. #define BUF_SIZE 1024
  7. int main()
  8. {
  9.     int pipefd[2];
  10.     pid_t pid;
  11.     char buf[BUF_SIZE];
  12.     int status;
  13.    
  14.     // 创建管道
  15.     if (pipe(pipefd) == -1) {
  16.         perror("pipe");
  17.         exit(EXIT_FAILURE);
  18.     }
  19.    
  20.     // 创建子进程
  21.     pid = fork();
  22.     if (pid == -1) {
  23.         perror("fork");
  24.         exit(EXIT_FAILURE);
  25.     }
  26.    
  27.     if (pid == 0) { // 子进程        
  28.         // 从管道中读取数据
  29.         if (read(pipefd[0], buf, BUF_SIZE) == -1) {
  30.             perror("read");
  31.             exit(EXIT_FAILURE);
  32.         }
  33.         
  34.         printf("子进程收到消息:%s\n", buf);
  35.         
  36.         // 发送消息给父进程
  37.         const char* message = "Hello, parent!";
  38.         if (write(pipefd[1], message, strlen(message) + 1) == -1) {
  39.             perror("write");
  40.             exit(EXIT_FAILURE);
  41.         }
  42.         close(pipefd[1]); // 关闭写端
  43.         exit(EXIT_SUCCESS);
  44.     } else { // 父进程
  45.         // 发送消息给子进程
  46.         const char* message = "Hello, child!";
  47.         if (write(pipefd[1], message, strlen(message) + 1) == -1) {
  48.             perror("write");
  49.             exit(EXIT_FAILURE);
  50.         }
  51.         
  52.         // 等待子进程退出
  53.         wait(&status);
  54.         if (WIFEXITED(status)) {
  55.             printf("子进程退出,返回值:%d\n", WEXITSTATUS(status));
  56.         }
  57.         
  58.         // 从管道中读取数据
  59.         if (read(pipefd[0], buf, BUF_SIZE) == -1) {
  60.             perror("read");
  61.             exit(EXIT_FAILURE);
  62.         }
  63.         printf("父进程收到消息:%s\n", buf);
  64.         close(pipefd[0]); // 关闭读端
  65.         
  66.         exit(EXIT_SUCCESS);
  67.     }
  68. }
复制代码
在这个示例代码中,父进程先向子进程发送一条消息,子进程收到消息后向父进程发送一条消息,并退出。父进程在等待子进程退出后再从管道中读取子进程发送的消息。

  • 编译并运行,打印如下
  1. 子进程收到消息:Hello, child!
  2. 子进程退出,返回值:0
  3. 父进程收到消息:Hello, parent!
复制代码
FIFO(命名管道)

FIFO(命名管道)是一种文件系统对象,与管道类似,也可以用于进程间通信。FIFO 是一种特殊类型的文件,它可以在文件系统中被创建,并且进程可以通过文件描述符来读取和写入数据。
与管道不同的是,FIFO 可以被多个进程打开,并且可以在文件系统中以路径的形式存在,因此不像管道那样只能在具有亲缘关系的进程之间使用。任何进程只要有相应的权限就可以打开 FIFO 并进行通信。
FIFO 的创建和使用

FIFO 的创建和使用也比较简单。首先需要使用 mkfifo() 函数创建 FIFO 文件,其原型如下
  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. int mkfifo(const char *pathname, mode_t mode);
复制代码
其中,pathname 是 FIFO 文件的路径名,mode 是文件的权限。
创建 FIFO 文件后,就可以像使用普通文件一样打开它,并使用 read() 和 write() 函数进行数据的读写。
下面是一个使用 FIFO 进行进程间通信的示例代码:
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <string.h>
  5. #include <sys/types.h>
  6. #include <sys/stat.h>
  7. #include <fcntl.h>
  8. #define FIFO_PATH "/tmp/myfifo"
  9. #define BUF_SIZE 1024
  10. int main()
  11. {
  12.     int fd;
  13.     char buf[BUF_SIZE];
  14.    
  15.     // 创建 FIFO 文件
  16.     if (mkfifo(FIFO_PATH, 0666) == -1) {
  17.         perror("mkfifo");
  18.         exit(EXIT_FAILURE);
  19.     }
  20.    
  21.     // 打开 FIFO 文件
  22.     fd = open(FIFO_PATH, O_RDWR);
  23.     if (fd == -1) {
  24.         perror("open");
  25.         exit(EXIT_FAILURE);
  26.     }
  27.    
  28.     // 向 FIFO 中写入数据
  29.     const char* message = "Hello, world!";
  30.     if (write(fd, message, strlen(message) + 1) == -1) {
  31.         perror("write");
  32.         exit(EXIT_FAILURE);
  33.     }
  34.    
  35.     // 从 FIFO 中读取数据
  36.     if (read(fd, buf, BUF_SIZE) == -1) {
  37.         perror("read");
  38.         exit(EXIT_FAILURE);
  39.     }
  40.    
  41.     printf("收到消息:%s\n", buf);
  42.    
  43.     // 关闭文件描述符并删除 FIFO 文件
  44.     close(fd);
  45.     if (unlink(FIFO_PATH) == -1) {
  46.         perror("unlink");
  47.         exit(EXIT_FAILURE);
  48.     }
  49.    
  50.     exit(EXIT_SUCCESS);
  51. }
复制代码
在这个示例代码中,程序先创建了一个 FIFO 文件 /tmp/myfifo,然后打开该文件并向其中写入一条消息。接下来从 FIFO 文件中读取数据,并将其打印出来。最后关闭文件描述符并删除 FIFO 文件。

  • 编译并运行,打印如下
  1. 收到消息:Hello, world!
复制代码
小结

Linux 中管道和 FIFO 是进程间通信的重要方式。管道只能用于亲缘关系的进程间通信,而 FIFO 可以被多个进程打开,不受进程之间关系的限制。无论是管道还是 FIFO,它们的使用方式都与普通文件类似,需要使用文件描述符和 read()、write() 函数来进行数据的读写。
在使用管道和 FIFO 进行进程间通信时,需要注意以下几点:

  • 管道和 FIFO 只能用于同一主机上的进程间通信,不能用于跨主机通信。
  • 管道和 FIFO 的读写操作是阻塞的,这意味着当一个进程尝试从一个空管道或 FIFO 中读取数据时,它会被阻塞,直到有数据可用为止。同样,当一个进程尝试将数据写入一个满的管道或 FIFO 时,它也会被阻塞,直到有空闲空间为止。
  • 在使用管道和 FIFO 进行进程间通信时,需要注意文件描述符的关闭顺序。
  • 管道和 FIFO 只能传输字节流,不能传输其他类型的数据,如结构体或指针。
  • 如果使用管道或 FIFO 进行进程间通信时,数据量较大,需要进行分段传输,否则可能会导致阻塞或缓冲区溢出等问题。
  • 管道和 FIFO 都是单向的,如果需要双向通信,则需要建立两个管道或 FIFO。
以上,如果觉得对你有帮助,点个赞再走吧,这样@知微之见也有更新下去的动力!
也欢迎私信我,一起交流!

来源:https://www.cnblogs.com/Wayne123/p/17218327.html
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

举报 回复 使用道具