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

Linux 进程间通信:命名管道(FIFO)实战指南

命名管道(FIFO)是 Linux 进程间通信的重要机制,通过文件系统路径打破亲缘进程限制。它基于内核缓冲区,遵循半双工原则,支持任意进程间的数据传输。创建需 mkfifo 或 open,打开时需遵循读写端同步规则以避免阻塞。实战中可用于文件拷贝及 C/S 模型通信,注意权限设置与资源清理。相比匿名管道,其优势在于通信范围更广且生命周期独立于进程。

Kubernet发布于 2026/3/23更新于 2026/7/2037 浏览
Linux 进程间通信:命名管道(FIFO)实战指南

Linux 进程间通信:命名管道(FIFO)实战指南

在 Linux 的 IPC(进程间通信)体系中,匿名管道解决了亲缘进程间的通信问题,但存在核心限制——仅支持具有共同祖先的进程。命名管道(FIFO)作为匿名管道的扩展,通过文件系统中的'命名'标识,打破了亲缘关系的束缚,实现了无关联进程间的双向数据传输。

一、命名管道核心概念

1.1 什么是 FIFO?

命名管道(Named Pipe),又称 FIFO(First In First Out),是一种特殊的文件系统对象(类型为 p)。其核心本质与匿名管道一致——内核中的一块缓冲区,但通过文件路径作为标识,让任意进程都能通过该路径访问管道。

与匿名管道相比,命名管道的核心差异在于'命名':

  • 匿名管道:无文件路径,仅通过 pipe() 创建的文件描述符在亲缘进程间共享。
  • 命名管道:有明确的文件路径(如 /tmp/myfifo),任意进程可通过 open() 打开该路径。

1.2 核心特性

  • 跨进程通信:支持无亲缘关系的进程(如两个独立的应用程序)通信。
  • 半双工通信:数据单向流动,如需双向通信需创建两个命名管道。
  • 基于文件操作:遵循 Linux'一切皆文件'思想,通过 open()/read()/write()/close() 等标准文件接口操作。
  • 生命周期随内核:创建后即使进程退出,管道文件仍存在于文件系统中,需手动删除(unlink() 或 rm 命令)。
  • 同步与互斥:内核自动保证管道操作的同步和互斥。

1.3 与匿名管道的对比

特性匿名管道 (pipe)命名管道 (FIFO)
定义半双工通道,用于亲缘进程特殊文件,允许无亲缘进程通信
创建方式pipe() 系统调用mkfifo() 函数或 mkfifo 命令
标识文件描述符文件系统路径
进程关系仅适用于有共同祖先适用于任意进程
持久性随进程关闭而销毁随文件系统存在,需手动删除
打开方式创建即打开需显式 open() 打开路径

两者在通信机制、数据模型(字节流)、阻塞行为上高度相似,唯一的区别在于创建与打开的方式。

二、命名管道的创建方式

命名管道有两种创建方式,本质都是在文件系统中生成一个 FIFO 类型的文件。

2.1 命令行创建

适合快速测试,语法简单:

# 创建名为 myfifo 的命名管道
mkfifo myfifo

# 查看管道文件(类型标识为 p)
ls -l myfifo

创建的管道文件最前面的标识是 p 开头。无论写入多少数据,文件大小通常保持不变,验证了它不是普通文件。

2.2 代码创建

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

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

#define FIFO_PATH "./myfifo"

int main() {
    // 创建命名管道,权限 0644
    int ret = mkfifo(FIFO_PATH, 0644);
    if (ret == -1) {
        // 若管道已存在,errno 为 EEXIST,可忽略该错误
        if (errno != EEXIST) {
            perror("mkfifo error");
            return 1;
        }
        printf("命名管道已存在\n");
    } else {
        printf("命名管道创建成功\n");
    }
    return 0;
}

三、命名管道的打开规则

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

打开方式行为描述
只读 (O_RDONLY)若无写端打开:阻塞;若指定 O_NONBLOCK:不阻塞,直接返回成功
只写 (O_WRONLY)若无读端打开:阻塞;若指定 O_NONBLOCK:不阻塞,返回失败 (ENXIO)
读写 (O_RDWR)不阻塞,直接打开(可实现单进程自我循环)

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

四、实战案例

4.1 案例 1:文件拷贝

通过两个程序配合,实现文件拷贝功能:写端读取本地文件写入管道,读端从管道读取写入目标文件。

写端程序 (file_writer.c)
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define FIFO_PATH "./tp"
#define BUF_SIZE 1024

#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0)

int main() {
    // 1. 创建命名管道
    int ret = mkfifo(FIFO_PATH, 0644);
    if (ret == -1 && errno != EEXIST) {
        ERR_EXIT("mkfifo error");
    }

    // 2. 打开本地文件(待拷贝的源文件)
    int infd = open("abc", O_RDONLY);
    if (infd == -1) {
        ERR_EXIT("open source file error");
    }

    // 3. 以写方式打开命名管道(阻塞,直到读端打开)
    int outfd = open(FIFO_PATH, O_WRONLY);
    if (outfd == -1) {
        ERR_EXIT("open fifo error");
    }

    // 4. 读取源文件内容,写入管道
    char buf[BUF_SIZE];
    int n;
    while ((n = read(infd, buf, BUF_SIZE)) > 0) {
        if (write(outfd, buf, n) != n) {
            ERR_EXIT("write to fifo error");
        }
    }

    close(infd);
    close(outfd);
    printf("文件内容写入管道完成\n");
    return 0;
}
读端程序 (file_reader.c)
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#define FIFO_PATH "./tp"
#define BUF_SIZE 1024

#define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0)

int main() {
    // 1. 以读方式打开命名管道(阻塞,直到写端打开)
    int infd = open(FIFO_PATH, O_RDONLY);
    if (infd == -1) {
        ERR_EXIT("open fifo error");
    }

    // 2. 创建目标文件
    int outfd = open("abc.bak", O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (outfd == -1) {
        ERR_EXIT("open target file error");
    }

    // 3. 从管道读取内容,写入目标文件
    char buf[BUF_SIZE];
    int n;
    while ((n = read(infd, buf, BUF_SIZE)) > 0) {
        if (write(outfd, buf, n) != n) {
            ERR_EXIT("write to target file error");
        }
    }

    close(infd);
    close(outfd);
    unlink(FIFO_PATH); // 手动删除管道文件
    printf("文件拷贝完成\n");
    return 0;
}
编译与运行
gcc file_writer.c -o writer
gcc file_reader.c -o reader

# 终端 1:运行读端(阻塞等待写端)
./reader

# 终端 2:运行写端(开始拷贝)
./writer

4.2 案例 2:Server-Client 通信

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

服务端程序 (server.cpp)

注:此示例使用了 C++ 标准库,建议保存为 .cpp 后缀编译

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

using namespace std;

const char* fifoname = "./myfifo";

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

    // 2. 打开管道文件(阻塞等待客户端连接)
    int rfd = open(fifoname, 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;
            cout << "client say: " << inbuffer << endl;
        } else if (n == 0) {
            break; // 写端关闭
        } else {
            perror("read");
            break;
        }
    }

    close(rfd);
    unlink(fifoname);
    return 0;
}
客户端程序 (client.cpp)
#include <iostream>
#include <string>
#include <cstdio>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

using namespace std;

const char* fifoname = "./myfifo";

int main() {
    // 1. 以写方式打开管道(阻塞,直到服务端打开读端)
    int wfd = open(fifoname, O_WRONLY);
    if (wfd < 0) {
        perror("open");
        return 1;
    }

    // 2. 循环输入并发送消息给服务端
    string outstring;
    while (true) {
        cout << "Please Enter@ ";
        cin >> outstring;
        write(wfd, outstring.c_str(), outstring.size());
    }

    close(wfd);
    return 0;
}
编译与运行
g++ server.cpp -o server
g++ client.cpp -o client

# 终端 1:启动服务端
./server

# 终端 2:启动客户端
./client

提示:必须先启动服务端再启动客户端,否则客户端会因无法找到读端而阻塞。

五、避坑指南与总结

常见陷阱

  1. 必须手动删除管道文件:命名管道创建后会残留于文件系统,若不删除,下次创建会报错(EEXIST),建议在通信结束后用 unlink() 删除。
  2. 避免单进程同时读写:虽然可通过 O_RDWR 打开管道实现单进程读写,但会破坏半双工特性,容易导致数据混乱。
  3. 处理阻塞场景:读端未打开时写端会阻塞,反之亦然。若需非阻塞操作,可在 open() 时添加 O_NONBLOCK 标志。
  4. 数据完整性保证:当写入数据量 ≤ PIPE_BUF(默认 4096 字节)时,内核保证原子性;超过则不保证,需在应用层处理分包。
  5. 权限设置合理:创建管道时权限需开放给通信进程,避免因权限不足导致 open() 失败。

总结

命名管道(FIFO)是匿名管道的重要扩展,核心价值在于突破了亲缘进程的限制,通过文件系统路径实现任意进程间的通信,且沿用了 Linux 标准的文件操作接口,上手成本低。

  • 它是带文件路径的内核缓冲区,支持跨进程通信。
  • 需通过 mkfifo() 或命令创建,open() 时需遵循读写端同步规则。
  • 实战中可实现文件拷贝、C/S 通信等场景。
  • 与匿名管道相比,核心优势是通信范围无限制,生命周期随内核。

如果需要更高效率的跨进程通信(如高频数据传输),后续可学习共享内存;若需消息结构化传输,可了解消息队列。

目录

  1. Linux 进程间通信:命名管道(FIFO)实战指南
  2. 一、命名管道核心概念
  3. 1.1 什么是 FIFO?
  4. 1.2 核心特性
  5. 1.3 与匿名管道的对比
  6. 二、命名管道的创建方式
  7. 2.1 命令行创建
  8. 创建名为 myfifo 的命名管道
  9. 查看管道文件(类型标识为 p)
  10. 2.2 代码创建
  11. 三、命名管道的打开规则
  12. 四、实战案例
  13. 4.1 案例 1:文件拷贝
  14. 写端程序 (file_writer.c)
  15. 读端程序 (file_reader.c)
  16. 编译与运行
  17. 终端 1:运行读端(阻塞等待写端)
  18. 终端 2:运行写端(开始拷贝)
  19. 4.2 案例 2:Server-Client 通信
  20. 服务端程序 (server.cpp)
  21. 客户端程序 (client.cpp)
  22. 编译与运行
  23. 终端 1:启动服务端
  24. 终端 2:启动客户端
  25. 五、避坑指南与总结
  26. 常见陷阱
  27. 总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • OpenClaw 本地 AI 智能体安装与配置指南
  • Python Wheel 文件 (.whl) 安装方法与常见问题解决
  • C++ 伸展树与红黑树原理及代码实现
  • AI 绘画工具背后的视觉技术:Stable Diffusion 解析
  • TRAE 与 VSCode 的 Git 工作流实战指南
  • Neo4j Desktop 2.0 安装及自定义路径配置指南
  • 把 Clawdbot 连上飞书:从配置到踩坑的实操笔记
  • OpenClaw 技能精选仓库:本地 AI 助手插件市场指南
  • 数据结构:八种常见排序算法详解
  • DeepSeek-R1 大模型基于 MS-Swift 框架部署、推理与微调指南
  • 上下文学习原理与实战代码解析
  • 边缘采集引擎:从 Python 迁移到 Go 的性能优化与实战方案
  • Fooocus 实战指南:基于 SDXL 的 AI 图像生成入门
  • prompts.chat 开源 AI 提示词库项目深度解析
  • 使用 Dexie 操作前端数据库 IndexedDB 教程
  • 九快记账:基于 Spring Boot 与 Flutter 的开源财务管理系统
  • AI 图形界面操作技术演进对职场岗位的影响分析
  • Servlet 与 JSP 作用域详解:生命周期与使用场景
  • YOLOv8 模型移植到高通机器人 RB5 平台详细指南
  • 大模型在机器视觉行业的落地路径

相关免费在线工具

  • 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