前言
之前在Windows环境下学习多进程ipc通信,总感觉少了点什么。刚好电脑里有Ubuntu虚拟机,里面也有qt环境,所以还是想实际跑一下Linux环境下的几种常见的进程间通信方式,加深理解。
本节中介绍的是命名管道FIFO,顾名思义我们需要创建一个指定名字的管道文件,然后利用它进行读写通信。它的概念和使用方法和之前的都有些相似,所以就不多说了。
一、命名管道(FIFO)
FIFO(First In, First Out) 是一种特殊类型的文件,它允许无关进程通过一个路径名进行通信。数据按顺序写入和读出,先进先出。
它有以下关键特性 :
1.有文件路径 ,如 /tmp/myfifo,像普通文件一样出现在文件系统中
2.不占磁盘空间,数据存在内核缓冲区中,不会写入硬盘
3.打开时阻塞 ,如果只有读端打开,会等写端;反之亦然(除非用 O_NONBLOCK)
4.单向通信 ,一个 FIFO 只能单向:要么读,要么写(要双向需两个 FIFO)
5.支持多对一/一对多 多个写者 → 一个读者(消息会交错!需协议分隔)
多个读者 ← 一个写者(只有一个读者能收到!)
⚠️ 重要:多个读者时,内核会随机选一个进程投递消息,其他读者收不到!所以通常是一对一或一写多读(但多读需自己协调)。
FIFO适合什么场景,有什么应用呢?
1.简单进程通信 两个无关程序(比如 Python 脚本和 C 程序)通过 /tmp/xxx 交换数据
2.调试友好 你可以用 cat、echo、hexdump 直接查看/注入数据
3.无需网络 比 TCP 快,比共享内存简单
4.天然同步 写者会等读者准备好(避免消息丢失)
实际应用例子
1.日志收集器
多个服务把日志写入 /var/log/app.fifo
一个日志守护进程从 FIFO 读取并写入文件或上传
2.控制接口
一个后台服务监听 /tmp/control.fifo
用户执行 echo "reload" > /tmp/control.fifo 来触发重载配置
3.Shell 脚本协作
二、终端测试
和之前的代码测试不同,fifo文件可以在终端直接通过Linux命令创建,并在两个终端中实现通信。

终端1:
(1)mkfifo /tmp/myfifo,在临时路径下创建管道文件
(2)ls -l /tmp/myfifo,确保文件生成成功
(3)cat/tmp/myfifo,将文件内容输出到终端。此时阻塞等待有内容可以输出。
终端2:
(4)echo "hello from writer!" > /tmp/myfifo,将文本内容输入到管道文件中
终端1:
(1)显示出终端2输入的内容,并退出
事后检查管道文件仍然存在,且可以重复利用。但一段时间后可能会被删除。
三、代码测试
新建writer.c:(稍微解释一下0666的意思,实际上等价于chmod 666 /tmp/myfifo,赋予了这个文件的rw读写权限。13则是字符串长度。)
cpp
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
int main() {
mkfifo("/tmp/myfifo", 0666);
int fd = open("/tmp/myfifo", O_WRONLY);
write(fd, "Hello FIFO!\n", 13);
close(fd);
return 0;
}
新建reader.c:
cpp
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
int fd = open("/tmp/myfifo", O_RDONLY);
char buf[100];
read(fd, buf, sizeof(buf));
printf("Read: %s", buf);
close(fd);
unlink("/tmp/myfifo"); // 删除
return 0;
}

四、总结
看上去,这也是属于利用文件进行通信的一种方式。但实际上还是有点区别的,fifo文件的存储位置在内核内存缓冲区,它的性能相比于真实的磁盘文件来说,效率会高一些。而且过程中自带原子性,内核也会自动阻塞和环形。如果需要高性能的本地ipc,fifo会比普通的文件队列更好。但如果考虑到崩溃后消息不丢,普通文件队列因为可以存储,会更加可靠。