跳到主要内容
极客日志极客日志
首页博客AI提示词GitHub精选代理工具
搜索
|注册
博客列表
C++算法

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

Linux 命名管道(FIFO)提供跨进程通信能力,突破匿名管道仅限血缘进程的限制。通过文件系统标识,任意进程可读写 FIFO 实现数据交互。创建方式、打开规则及阻塞机制,结合 C++ 代码演示服务端与客户端的完整通信流程,并总结常见陷阱如阻塞处理、信号忽略及文件清理,帮助开发者掌握基础 IPC 方案。

Stephaine Walsh发布于 2026/3/23更新于 2026/5/14 浏览
Linux 命名管道(FIFO)通信:原理与跨进程实战

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

在 Linux 进程间通信(IPC)中,管道是最基础的方式之一。但平时接触的'匿名管道'有个局限——只能用于有血缘关系的进程(如父子进程),无法实现无关联进程间的通信。

命名管道(FIFO) 正是为了解决这个问题而生。它给管道赋予了一个文件名,通过文件系统作为媒介,让任意两个进程都能通过这个'命名'实现数据交互。

一、先搞懂:命名管道是什么?

1. 核心本质

命名管道和匿名管道的底层逻辑一致,都是基于字节流的半双工通信,依赖内核缓冲区。区别在于:命名管道有一个可见的文件系统入口。这个文件只是一个标识,不存储实际数据,而匿名管道没有文件入口,只能通过文件描述符继承。

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

2. 关键特性

  • 跨进程通信:无血缘关系的进程也能通信。
  • 半双工:数据单向流动,双向需创建两个 FIFO。
  • 阻塞特性:默认打开读端会阻塞直到有写端,反之亦然(可通过 O_NONBLOCK 调整)。
  • 生命周期:文件不会随进程退出自动删除,需手动清理。
对比维度匿名管道 (pipe)命名管道 (FIFO)
通信范围有血缘关系进程任意进程
标识方式无文件标识文件系统入口
创建方式pipe() 系统调用mkfifo() 或命令
生命周期随进程退出销毁随文件删除销毁

二、创建与打开规则

1. 创建方式

可以通过命令行或代码创建,本质都是在文件系统生成一个 FIFO 类型文件。

命令行创建

# 创建名为 myfifo 的管道
mkfifo myfifo
# 查看文件类型(p 开头表示管道)
ls -l myfifo

代码创建 使用 mkfifo() 函数,需指定路径和权限。

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


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

2. 打开规则

命名管道的 open() 行为与普通文件不同,核心是读端与写端的同步。只有当两端都被打开后,通信才能正常进行。

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

注意:实际开发中,建议读端用 O_RDONLY,写端用 O_WRONLY。

三、实操:手搓通信程序

我们来实现一个简单的 C/S 模型。服务端监听管道接收消息,客户端发送消息。

1. 项目结构

为了规范编译,我们准备 Makefile 和公共头文件。

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 确保权限正确
    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. 运行步骤

  1. 编译:make
  2. 启动服务端:./server &
  3. 启动客户端:./client
  4. 输入内容即可看到服务端输出。

四、常见坑点总结

在实际使用中,有几个地方容易踩坑:

  1. 忘记处理阻塞:打开 FIFO 时未设置 O_NONBLOCK,导致进程卡死。如果业务需要非阻塞,记得加上标志位。
  2. 忽略 SIGPIPE 信号:读端关闭后,写端继续写入会导致进程崩溃,应捕获该信号或检查返回值。
  3. FIFO 文件残留:程序退出后未用 unlink() 删除 FIFO,下次创建时报错。务必做好清理工作。
  4. 路径不一致:读写两端使用的 FIFO 路径必须完全一致,否则无法通信。
  5. 权限问题:mkfifo() 设置的权限过低可能导致其他进程无法打开,建议测试环境设为 0666。

五、结语

命名管道是 Linux 跨进程通信的基础,核心在于利用文件系统标识实现任意进程间的字节流通信。它继承了匿名管道的简单性,又解决了血缘限制的问题。

掌握 FIFO 的阻塞特性、信号处理和文件清理机制,就能应对大多数基础 IPC 场景。后续若涉及更复杂的优先级或双向通信需求,可进一步探索消息队列或共享内存,但理解 FIFO 是入门的关键。

目录

  1. Linux 命名管道(FIFO)通信:原理与跨进程实战
  2. 一、先搞懂:命名管道是什么?
  3. 1. 核心本质
  4. 2. 关键特性
  5. 二、创建与打开规则
  6. 1. 创建方式
  7. 创建名为 myfifo 的管道
  8. 查看文件类型(p 开头表示管道)
  9. 2. 打开规则
  10. 三、实操:手搓通信程序
  11. 1. 项目结构
  12. 2. 服务端 (server.cpp)
  13. 3. 客户端 (client.cpp)
  14. 4. 运行步骤
  15. 四、常见坑点总结
  16. 五、结语
  • 💰 8折买阿里云服务器限时8折了解详情
  • GPT-5.5 超高智商模型1元抵1刀ChatGPT中转购买
  • 代充Chatgpt Plus/pro 帐号了解详情
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • STL 底层揭秘:map/set 如何封装红黑树及迭代器实现
  • 学术论文降重与 AIGC 检测应对策略指南
  • Magic API 低代码接口开发平台完全指南
  • Neo4j 5.26 版本安装、下载及配置步骤
  • 双指针算法:三数之和
  • Spring Boot 微服务架构设计与实战
  • Python Pandas 核心数据结构与操作实战指南
  • Stable Diffusion WebUI 本地部署指南(Win 11 + NVIDIA GPU)
  • 基于 OpenAI、LangChain 和 MongoDB 构建 AI Agent
  • Docker 拉取镜像及搜索失败问题完整解决方案
  • Visual Studio Code 核心特性与实战体验
  • GitHub Copilot Plan Mode 结合多模型路由的复杂项目实战
  • CustomTkinter 入门:使用 Python 构建现代化桌面应用
  • 前端调试入门:如何使用 debugger 设置断点
  • 数据结构详解:图的存储结构与经典算法解析
  • GitHub Copilot 网络配置与代理优化实战指南
  • AI 时代如何脱颖而出:商业认知与行动策略
  • JWT(JSON Web Token)结构化知识体系详解
  • Python 使用 Tkinter 实现满屏祝福弹窗
  • Stable Diffusion 模型加载错误修复指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • 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