Linux 进程通信之:命名管道 (FIFO)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/afei__/article/details/84131150

一、简介

由于管道(Pipe)只能应用于存在血缘关系的进程间通信,为了突破这个限制,使用命名管道(FIFO)来实现 不相干进程间 的通信。

FIFO 是 Linux 基础文件类型中的一种,它并不占用磁盘上实际的数据块,而仅仅是标识内核中的一条通道。各进程可以打开这个文件进行 read/write,实际上是在读写内核通道。

二、API 说明

1. 头文件

#include <sys/types.h>
#include <sys/stat.h>

2. 创建一个 FIFO 文件

int mkfifo(const char *pathname, mode_t mode);

3. 参数说明

  • pathname : 指定创建的文件路径名
  • mode : 指定文件的访问权限,实际为一个形如 “rwxrwxrwx” 的 int 值,分别表示 “所有者”“所在组”“其他组” 的用户访问权限。r 为可读,值为 1;w 为可写,值为 2;x 为可执行,值为 4。通常使用八进制数来表示权限。例如 0775

4. 返回值说明

成功返回 0,失败返回 -1,并设置相应的 errno

注意 :如果文件已存在,也会返回 -1,创建失败的错误原因是:文件已存在。

三、命名管道的打开规则

1. 说明

注意,mkfifo 方法只是创建了一个这样的文件,可供其它进程操作。而其它进程想要使用该文件进行通信,还是需要像文件操作一样,打开读或写关闭 文件的。

2. 打开规则

打开 FIFO 文件通常有四种方式,即:

open(const char *path, O_RDONLY); // 只读的方式打开(会堵塞)
open(const char *path, O_RDONLY | O_NONBLOCK); // 非堵塞的只读方式打开
open(const char *path, O_WRONLY); // 只写的方式打开(会堵塞)
open(const char *path, O_WRONLY | O_NONBLOCK); // 非堵塞的只写方式打开

3. 规则说明

O_RDONLYO_WRONLY 我们已经很熟悉了,但 O_NONBLOCK 是什么意思呢?

O_NONBLOCK 表示非堵塞的方式,默认情况下,打开 FIFO 是会堵塞进程的。例如我们的 A 进程使用只读的方式打开文件时,此时它会被堵塞住,直到有一个 B 进程以只写的方式打开了同一个 FIFO 文件。同理,先以只写的方式打开,也会堵塞住,直到有一个进程以只读的方法打开同一个 FIFO 文件。

可能会觉得有点晕,下面通过一个实际例子,并给出运行的 gif 图,来理解堵塞的含义。

示例

1. 写进程

将一个 Hello World 写到 FIFO 文件中去。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main() {
    char pathname[] = "my_fifo";
    char buf[] = "Hello World\n";
    mkfifo(pathname, 0775);
    int fd = open(pathname, O_WRONLY);
    if (fd == -1) {
        perror("open failed\n");
        exit(EXIT_FAILURE);
    }
    write(fd, &buf, strlen(buf));
    printf("write done\n");
    close(fd);
    return 0;
}

2. 读进程

读取 FIFO 文件中的信息,并输出到标准输出流中。

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main() {
    char pathname[] = "my_fifo";
    char buf[127] = { 0 };
    mkfifo(pathname, 0775);
    int fd = open(pathname, O_RDONLY);
    if (fd == -1) {
        perror("open failed\n");
        exit(EXIT_FAILURE);
    }
    int n;
    while ((n = read(fd, buf, 10)) > 0) {
        write(STDOUT_FILENO, &buf, n);
    }
    close(fd);
    return 0;
}

3. 运行示例

先执行读的程序,open 会堵塞住等待读入,再执行写的程序,两个进程都成功执行完毕。

同理反过来,先执行写的程序,也会一直堵塞等待。

在这里插入图片描述

这里展示的是先执行 的进程,再执行 的进程,可以观察到确实会有堵塞的情况。

反过来也是一样的会有先堵塞 进程,直到 进程执行时结束。

猜你喜欢

转载自blog.csdn.net/afei__/article/details/84131150