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

Linux 命名管道 FIFO 实战:跨进程通信与常见坑

命名管道为 Linux 跨进程通信提供了简单方式,通过文件系统入口让任意进程基于字节流交互。创建后用 open 打开时必须成对出现,默认阻塞。通过 C++ 示例演示了服务端客户端通信,并总结了阻塞、SIGPIPE、文件残留等常见问题。掌握这些就能应对日常的 IPC 需求。

奇形怪状发布于 2026/6/30更新于 2026/8/2319 浏览
Linux 命名管道 FIFO 实战:跨进程通信与常见坑

Linux 下的管道通信大家都不陌生,但匿名管道只能父子进程用,碰上没血缘关系的进程就抓瞎了。命名管道(FIFO)就是为这种事准备的——它给管道一个文件系统入口,任何进程只要知道路径就能通信。

这篇文章记录我使用 FIFO 的过程,包括创建、通信和那些容易掉的坑。

命名管道是什么?

命名管道本质上和匿名管道一样,都是内核缓冲区的字节流,半双工(单向流动)。区别在于它有一个'文件'挂在文件系统上,类型标识为 p。这个文件不存数据,只是一个入口。因为有了这个可见的路径,无关进程就能通过 open 获取读写描述符,直接通信。

文章配图 文章配图

关键特性:

  • 半双工,想双向就得建两个 FIFO。
  • 打开时默认阻塞:读端打开会等写端,写端会等读端,除非设置 O_NONBLOCK。
  • 进程退出后 FIFO 文件还在,得手动 unlink 删除。
  • 跨进程通信,跟血缘没关系。

创建命名管道

两种方式:命令行 mkfifo 命令,或者代码里调用 mkfifo 函数。

命令行方式

mkfifo myfifo
ls -l myfifo   # 看到文件类型是 p,大小永远是 0

你往里面写多少数据,文件大小都不变,证实它只是个标识。

代码方式(mkfifo 函数)

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

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("FIFO already exists\n");
    } else {
        printf("FIFO created\n");
    }
    return 0;
}

打开 FIFO 的规则

用 open 打开时行为比较特殊,核心是读端和写端必须'配对'才能继续:

  • 只读打开(O_RDONLY)默认阻塞,直到有人用只写打开。
  • 只写打开(O_WRONLY)默认阻塞,直到有人用只读打开。
  • 读写模式(O_RDWR)不阻塞,但通常不建议用,容易搞乱通信方向。

实际使用中,读端就 O_RDONLY,写端就 O_WRONLY,清晰明了。

写个例子:服务端与客户端通信

下面用 C++ 写一个简单的 server 和 client,通过 FIFO 传递字符串。

公共头文件 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

服务端 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];
    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;
        }
    }

    close(rfd);
    unlink(fifoname.c_str());   // 删掉 FIFO 文件
    return 0;
}

客户端 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());
        // 不用写 '\0'
    }
    close(wfd);
    return 0;
}

编译运行:先执行 make,然后一个终端运行 ./server,另一个终端 ./client,输入内容就能看到服务端打印。

实际用到的地方

我刚接触 IPC 时,FIFO 常用来做日志服务的前端交互。后台守护进程开一个 FIFO 监听,工具程序往里写命令,控制日志级别或输出目标,简单又可靠。当然,两个独立服务之间传数据也能用它,复杂场景就得上消息队列了。

容易掉的坑

  • 阻塞问题:忘了设 O_NONBLOCK,程序启动就卡住,还以为是 bug。打开前先确认对面会来。
  • SIGPIPE 信号:读端关闭后写端继续写,进程会收到 SIGPIPE,默认动作是终止。可以忽略信号或处理它,但最好保证读端存活。
  • 文件残留:每次创建前看看文件在不在,或者退出时用 unlink 清掉。长期运行的环境里,/tmp 下可能一堆 FIFO。
  • 路径统一:读写双方路径必须完全一致,一个用相对路径一个用绝对路径就会找不到。
  • 权限:mkfifo 给的 mode 太低,其他用户就打不开。0666 一般够用。
  • 字节流边界:TCP 也有类似问题,每次读的数据可能不是完整的消息,需要自己定界。这里只是简单示例,读固定大小缓冲区,实际项目注意处理。

写完这些,FIFO 的基本用法就差不多了。它本质不复杂,知道它怎么工作的,再加上留意上面几个坑,完全可以应付一般的跨进程通信需求。后面如果想效率更高或者需要双向多路,可以再看看消息队列和共享内存。

目录

  1. 命名管道是什么?
  2. 创建命名管道
  3. 打开 FIFO 的规则
  4. 写个例子:服务端与客户端通信
  5. 实际用到的地方
  6. 容易掉的坑
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • Stable Diffusion 云端部署:电商商用场景与成本透明化
  • 从 Webhook 到 OpenClaw:钉钉周报提醒机器人的演进
  • 74 个低空无人机 AI 算法详解
  • Python 在 PyCharm 中使用 environment.yml 文件配置虚拟环境
  • 内网安全:隧道技术详解
  • 社招 FPGA 面试核心考点:基础概念与架构解析
  • Claude Code 终端三件套:Ghostty + Yazi + Lazygit 打造高效开发环境
  • 利用 LLM 和 Python 进行股价预测实战
  • Spec-Kit 实战指南:从规范到代码的全流程自动化落地
  • MyBatisPlus 与 Thymeleaf 全栈分页整合方案
  • 使用 Selenium 搭建免费 Web 搜索 API 服务
  • 深度学习模型训练和部署的基本步骤
  • 大模型项目实战与开发流程详解
  • local-dream 项目实现安卓端 Stable Diffusion 高效运行与骁龙 NPU 加速
  • Spring AI Tool 实现自然语言操作 MySQL 数据库详解
  • Mac M3 安装 Antigravity Agent 显示已损坏问题解决方案
  • LLaMA-3 本地部署指南:Ollama 与 Open WebUI 搭建
  • PlantUML 绘图工具简介与使用指南
  • Kubernetes 与 AI 推理服务最佳实践
  • RAP-MCTS 算法详解:大模型思维链

相关免费在线工具

  • 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