跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

Linux 命名管道(FIFO)跨进程通信:原理与实战

Linux 命名管道(FIFO)通过文件系统实现无血缘关系进程间的字节流通信。它解决了匿名管道仅限父子进程的局限,具备半双工、阻塞及文件标识特性。 mkfifo 创建方式、读写规则及 C++ 实战代码,涵盖服务端监听与客户端发送逻辑,并总结常见阻塞、信号处理及权限坑点,帮助开发者掌握基础 IPC 机制。

1qazxsw2发布于 2026/3/28更新于 2026/10/575 浏览
Linux 命名管道(FIFO)跨进程通信:原理与实战

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

在 Linux 进程间通信(IPC)中,管道是最基础的方式之一。但常用的匿名管道有一个局限——只能用于有血缘关系的进程(如父子进程)。命名管道(FIFO) 则通过文件系统作为媒介,让任意两个进程(无论是否有血缘关系)都能实现数据交互。

一、命名管道是什么?

1. 本质区别

命名管道和匿名管道的核心通信逻辑一致,都是基于内核缓冲区的字节流半双工通信。核心区别在于:命名管道有一个可见的文件系统入口(一个 FIFO 文件),而匿名管道没有。

简单来说,匿名管道是'隐式的、血缘专属',命名管道是'显式的、通用的'。只要知道 FIFO 文件的路径,任意进程都能与之通信。

2. 核心特点

  • 跨进程通信:无血缘关系的进程可通过 FIFO 路径通信;
  • 半双工通信:数据单向流动,双向通信需创建两个 FIFO;
  • 基于文件标识:FIFO 存在于文件系统中,通过打开文件获取描述符;
  • 阻塞特性:默认读端阻塞直到写端打开,反之亦然(可设 O_NONBLOCK 非阻塞);
  • 生命周期:FIFO 文件不会随进程退出自动删除,需手动清理。

FIFO 结构示意

3. 对比匿名管道

维度匿名管道 (pipe)命名管道 (FIFO)
通信范围有血缘关系进程任意进程
标识方式无文件,靠 FD 继承有文件系统入口
创建方式pipe() 系统调用mkfifo() 或命令
生命周期进程退出销毁文件删除才销毁

二、创建方式

1. 命令行创建

使用 mkfifo 命令快速测试:

# 创建名为 myfifo 的管道
mkfifo myfifo
# 查看类型标识为 p
ls -l myfifo

创建的管道文件最前面的标识是 p,验证了它不是普通文件,写入时文件大小不变。

2. 代码创建

通过 mkfifo() 系统调用在代码中创建,需指定路径和权限:

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

// 参数:pathname-管道路径;mode-权限
int mkfifo(const char *pathname, mode_t mode);

示例:

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

#define FIFO_PATH "./myfifo"

int main() {
    int ret = mkfifo(FIFO_PATH, 0644);
    if (ret == -1) {
        if (errno != EEXIST) {
            perror("mkfifo error");
            return 1;
        }
        printf("命名管道已存在\n");
    } else {
        printf("命名管道创建成功\n");
    }
    return 0;
}

3. 打开规则

命名管道的 open() 行为与普通文件不同,关键在于读写端的同步:

  • O_RDONLY:只读(读端),默认阻塞,直到有写端打开;
  • O_WRONLY:只写(写端),默认阻塞,直到有读端打开;
  • O_RDWR:读写同时打开,不阻塞(可实现自我循环,但建议避免)。

注意:实际开发中,建议读端用 O_RDONLY,写端用 O_WRONLY,避免混用导致逻辑混乱。

三、实操实现

本例包含服务端(监听接收)和客户端(发送消息)。

1. 前置准备

comm.h

#pragma once
#include <string>
const std::string fifoname = "fifo";

Makefile

all: client server
client: client.cpp
g++ -o $@ $^ -std=c++11
server: server.cpp
g++ -o $@ $^ -std=c++11
.PHONY: clean
clean:
	rm -f client server

2. 服务端程序 (server.cpp)

#include <iostream>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include "comm.h"

int main() {
    // 1. 创建管道文件
    umask(0);
    int n = mkfifo(fifoname.c_str(), 0666);
    if (n < 0) {
        perror("mkfifo");
        return 1;
    }

    // 2. 打开管道文件(读端)
    int rfd = open(fifoname.c_str(), O_RDONLY);
    if (rfd < 0) {
        perror("open");
        return 2;
    }

    char inbuffer[1024];
    // 3. 通信循环
    while (true) {
        ssize_t n = read(rfd, inbuffer, sizeof(inbuffer) - 1);
        if (n > 0) {
            inbuffer[n] = 0;
            std::cout << "client say# " << inbuffer << std::endl;
        } else if (n == 0) {
            // 写端关闭
            break;
        } else {
            perror("read");
            break;
        }
    }

    // 4. 清理
    close(rfd);
    unlink(fifoname.c_str());
    return 0;
}

3. 客户端程序 (client.cpp)

#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "comm.h"

int main() {
    // 打开管道文件(写端)
    int wfd = open(fifoname.c_str(), O_WRONLY);
    if (wfd < 0) {
        perror("open");
        return 1;
    }

    std::string outstring;
    while (true) {
        std::cout << "Please Enter@ ";
        std::cin >> outstring;
        write(wfd, outstring.c_str(), outstring.size());
    }

    close(wfd);
    return 0;
}

4. 编译运行

在终端分别启动服务端和客户端即可看到交互效果。

四、应用场景

  • 后台服务与前台程序通信:守护进程接收指令;
  • 独立程序数据交互:如数据库与缓存服务传递数据;
  • Shell 脚本通信:比匿名管道更灵活;
  • 简单 C/S 模型:客户端写入请求,服务器读取处理。

五、常见坑点

  • 阻塞问题:未设置 O_NONBLOCK 导致进程卡死;
  • SIGPIPE 信号:读端关闭后写端继续写入会崩溃,需处理信号;
  • 文件残留:未 unlink() 导致下次创建报错;
  • 路径不一致:两端路径不同无法通信;
  • 权限问题:权限过低导致其他进程无法打开;
  • 数据边界:字节流无边界,需注意读取完整性。

六、总结

命名管道(FIFO)是 Linux 跨进程通信的基础,核心是通过文件系统标识实现任意进程间的字节流通信。它继承了匿名管道的简单性,又解决了血缘限制。掌握其阻塞特性、信号处理和文件清理机制,是学习 IPC 的关键一步。后续若需更高效率或复杂功能,可进一步探索消息队列或共享内存。

目录

  1. Linux 命名管道(FIFO)跨进程通信
  2. 一、命名管道是什么?
  3. 1. 本质区别
  4. 2. 核心特点
  5. 3. 对比匿名管道
  6. 二、创建方式
  7. 1. 命令行创建
  8. 创建名为 myfifo 的管道
  9. 查看类型标识为 p
  10. 2. 代码创建
  11. 3. 打开规则
  12. 三、实操实现
  13. 1. 前置准备
  14. 2. 服务端程序 (server.cpp)
  15. 3. 客户端程序 (client.cpp)
  16. 4. 编译运行
  17. 四、应用场景
  18. 五、常见坑点
  19. 六、总结

更多推荐文章

查看全部
  • Python 开发实战:集成本地 DocsGPT 构建智能 IDE
  • Python 基础语法完全指南:变量、数据类型与运算符详解
  • ComfyUI Manager 高效管理指南:提升 AI 绘画工作流效率
  • 20 款主流 AI 编程工具深度对比:IDE、编辑器与 Agent 选型指南
  • 人大金仓 KingBase 更换授权文件(Linux 和 Windows)
  • 春晚机器人集群:分布式实时协同算法与灵巧手实现
  • 六自由度机器人逆运动学解析与 MATLAB 实现
  • 注意力机制与 Transformer 模型实战:TensorFlow 实现机器翻译
  • 大规模无人机检测数据集:11998 张图像支持 YOLOv8/COCO/TensorFlow 训练
  • 大模型提示词工程核心技巧与实战应用指南
  • 低代码 AI 平台:Coze 与 Dify 深度对比
  • ANTLR4 C++ 实战进阶:构建高性能语法解析器
  • Coze 打造专属 AI 应用:从智能体到 Web 部署
  • Python 爬虫入门:基础类库与实战案例详解
  • 魔因漫创实战:集成中转 API 实现低成本 AI 漫画视频创作
  • 滑动窗口算法深度解析:LeetCode 经典例题实战
  • 深圳机器人产业地图:核心企业与研发方向梳理
  • Linux 进程概念详解:冯诺依曼体系与操作系统
  • AIGC 与现代教育技术
  • 数据结构:快速排序非递归实现、优化及内省排序详解

相关免费在线工具

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

  • JSON 压缩

    通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

  • JSON美化和格式化

    将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online