Linux命名管道(FIFO)通信:从原理到实操,一文搞懂跨进程通信

Linux命名管道(FIFO)通信:从原理到实操,一文搞懂跨进程通信

🔥个人主页:Cx330🌸

❄️个人专栏:《C语言》《LeetCode刷题集》《数据结构-初阶》《C++知识分享》

《优选算法指南-必刷经典100题》《Linux操作系统》:从入门到入魔

《Git深度解析》:版本管理实战全解

🌟心向往之行必能至


🎥Cx330🌸的简介:


目录

前言:

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

1. 命名管道的本质

2. 命名管道的核心特点

3. 命名管道与匿名管道的对比

二. 命名管道的创建方式

2.1 命令行创建(mkfifo 命令)

2.2 代码创建(mkfifo 函数)

2.3 命名管道的打开规则

三、实操实现:手搓命名管道通信

3.1 前置准备(Makefile && comm.h)

3.2 服务端程序(server.c)

3.3 客户端程序(client.c)

3.4 编译运行

四、命名管道的实际应用场景

五、常见坑点总结(必看)

六、总结


前言:

在Linux进程间通信(IPC)中,管道是最基础、最常用的通信方式之一,但我们平时接触的“匿名管道”有一个致命缺陷——只能用于有血缘关系的进程(父进程与子进程、兄弟进程),无法实现无关联进程间的通信。

命名管道(简称FIFO),正是为解决这个问题而生。它给管道赋予了一个“文件名”,通过文件系统作为媒介,让任意两个进程(无论是否有血缘关系)都能通过这个“命名”实现数据交互。今天这篇博客,就从原理到实操,手把手教你搞懂Linux命名管道,亲手实现跨进程通信。

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

1. 命名管道的本质

命名管道和匿名管道的核心通信逻辑完全一致——都是基于“字节流”的半双工通信(同一时刻只能单向传输数据),底层都是内核中的缓冲区。

两者的核心区别的是:命名管道有一个可见的文件系统入口(一个以.fifo或.pipe为后缀的文件),这个文件只是一个“标识”,不存储实际数据(数据仍在内存缓冲区中);而匿名管道没有文件入口,只能通过父子进程继承文件描述符来通信

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

2. 命名管道的核心特点

  • 跨进程通信:无血缘关系的进程(如两个独立的程序),只要知道FIFO文件路径,就能通过它通信;
  • 半双工通信:数据只能单向流动,若要实现双向通信,需要创建两个FIFO(一个用于A→B,一个用于B→A);
  • 基于文件标识:FIFO文件存在于文件系统中,进程通过打开这个文件,获取读写文件描述符,进而实现通信;
  • 阻塞特性:默认情况下,打开FIFO的读端会阻塞,直到有进程打开写端;打开写端也会阻塞,直到有进程打开读端(可通过O_NONBLOCK设置为非阻塞);
  • 生命周期:FIFO文件不会随进程退出而自动删除,需要手动删除(rm命令或unlink函数),否则会一直存在于文件系统中。

3. 命名管道与匿名管道的对比

为了更清晰区分,做一个简单对比表,避免混淆:

对比维度

匿名管道(pipe)

命名管道(FIFO)

通信范围

有血缘关系的进程(父子、兄弟)

任意进程(无血缘关系也可)

标识方式

无文件标识,通过文件描述符继承

有文件系统入口(FIFO文件)

创建方式

通过pipe()系统调用创建

通过mkfifo()系统调用或mkfifo命令创建

生命周期

随进程退出而销毁(文件描述符关闭)

随FIFO文件删除而销毁,进程退出不影响文件

使用场景

父子进程间简单通信(如shell管道)

无关联进程间通信(如两个独立程序交互)


二. 命名管道的创建方式

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

2.1 命令行创建(mkfifo 命令)

直接通过mkfifo命令创建命名管道,语法简单,适合快速测试:

# 创建名为myfifo的命名管道 mkfifo myfifo # 查看管道文件(类型标识为p) ls -l myfifo 
我们可以发现,这里创建的管道文件(最前面的标识是p开头),就算我们是不停的在往里面进行写操作,但是它的文件大小是一直不变的,验证了我们上面图中所说的它不是一个普通文件。

2.2 代码创建(mkfifo 函数)

通过 mkfifo()系统调用在代码中创建命名管道,需指定管道路径和权限,原型如下:

#include <sys/stat.h> #include <sys/types.h> // 参数:pathname-管道路径;mode-权限(如0644) 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() { // 创建命名管道,权限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; } 

2.3 命名管道的打开规则

命名管道的打开(open())行为与普通文件不同,核心是 “读端与写端的同步”—— 仅当管道的读端和写端都被打开后,通信才能正常进行,具体规则如下:

  • O_RDONLY:以只读方式打开(读端),默认阻塞,直到有进程以O_WRONLY方式打开;
  • O_WRONLY:以只写方式打开(写端),默认阻塞,直到有进程以O_RDONLY方式打开;
  • O_RDWR:以读写方式打开,不阻塞,直接打开(同时具备读和写权限,可实现单向通信的 “自我循环”)
注意:实际开发中,建议读端O_RDONLY打开,写端O_WRONLY打开,避免使用O_RDWR(可能导致通信逻辑混乱)。

三、实操实现:手搓命名管道通信

  • server.c:作为服务端,监听管道,接收客户端消息并打印;
  • client.c:作为客户端,向管道发送消息,实现双向交互。

3.1 前置准备(Makefile && comm.h)

Makefile:

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

comm.h:

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

3.2 服务端程序(server.c)

#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); // 5.删除管道文件 unlink(fifoname.c_str()); return 0; }

3.3 客户端程序(client.c)

#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; }

3.4 编译运行


四、命名管道的实际应用场景

命名管道因其“跨进程、简单易用”的特点,在Linux开发中应用广泛,常见场景包括:

  • 后台服务与前台程序通信:如后台守护进程(如日志服务),通过FIFO接收前台程序发送的日志指令,实现日志的动态控制;
  • 多个独立程序的数据交互:如两个不同的服务程序(如数据库服务和缓存服务),通过FIFO传递数据,无需复杂的IPC机制;
  • shell脚本间通信:在shell脚本中,通过mkfifo命令创建FIFO,实现两个脚本之间的数据传输(比匿名管道更灵活);
  • 简单的客户端/服务器模型:基于FIFO实现简单的C/S架构,客户端向FIFO写入请求,服务器从FIFO读取请求并处理,返回结果。

五、常见坑点总结(必看)

  • 忘记处理阻塞:打开FIFO时未设置O_NONBLOCK,导致进程一直阻塞,误以为程序卡死;
  • 忽略SIGPIPE信号:读端关闭后,写端继续写入,导致进程崩溃;
  • FIFO文件残留:未用unlink()删除FIFO,下次创建时报错;
  • 路径不一致:读端和写端使用的FIFO路径不同,导致无法通信;
  • 权限问题:mkfifo()设置的权限过低(如0600),导致其他进程无法打开FIFO,建议设置为0666;
  • 数据错乱:未处理字节流无边界问题,读端读取的数据不完整或拼接错误。

六、总结

命名管道(FIFO)是Linux跨进程通信的基础方式,核心是“通过文件系统标识,实现任意进程间的字节流通信”。它继承了匿名管道的简单性,又解决了匿名管道“只能用于血缘进程”的缺陷,是入门IPC开发的必学知识点。

本文通过“原理→API→实操→避坑”的流程,手把手教你实现命名管道的单方向和双向通信,代码可直接复用。重点掌握FIFO的阻塞特性、SIGPIPE信号处理和文件删除问题,就能避免绝大多数踩坑场景。

实际开发中,若需要更高效、更复杂的通信(如消息优先级、双向通信的更优实现),可后续学习消息队列、共享内存等IPC机制,但命名管道的核心思想(字节流、文件标识),是理解所有IPC机制的基础。

最后,附上本文所有实操代码的仓库链接,方便大家下载测试和修改:fifo

Read more

2025年12月GESPC++一级真题解析(含视频)

2025年12月GESPC++一级真题解析(含视频)

视频讲解:GESP2025年12月一级C++真题讲解 一、单选题 第1题 解析: 答案B,“飞行控制系统执行判断”就是处理器 第2题 解析: 答案A,BCD都不会导致编译错误 第3题 解析: 答案A,for是关键字 第4题 解析: 答案C,逗号表达式,每个语句都执行,输出最后一个语句 第5题 解析: 答案B, 2+3*4%5 =2+12%5 =2+2 =4 第6题 解析: 答案A, b=a=4; =符号,从右往左执行 先执行a=4,返回4 b=返回结果4

By Ne0inhk
C++ 多态详解:从概念本质、语法规则到底层实现,结合实战代码的全方位指南

C++ 多态详解:从概念本质、语法规则到底层实现,结合实战代码的全方位指南

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 多态的概念:从“多种形态说起” * 1.1 多态的概念解析 * 1.2 生活中的多态示例 * 二. 多态的构成条件和核心语法 * 2.1 条件 1:虚函数的定义 * 2.2 条件 2:虚函数的重写(覆盖) * 2.3 多态场景的一个笔试选择题(重要): * 三、虚函数重写的特殊情况 * 3.1 协变(了解) * 3.2 析构函数的重写(重点)

By Ne0inhk
Java毕设项目推荐-基于SpringBoot的小区水资源管理系统基于springboot的小区水务系统设计与实现【附源码+文档,调试定制服务】

Java毕设项目推荐-基于SpringBoot的小区水资源管理系统基于springboot的小区水务系统设计与实现【附源码+文档,调试定制服务】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围::小程序、SpringBoot、SSM、JSP、Vue、PHP、Java、python、爬虫、数据可视化、大数据、物联网、机器学习等设计与开发。 主要内容:免费开题报告、任务书、全bao定制+中期检查PPT、代码编写、🚢文编写和辅导、🚢文降重、长期答辩答疑辅导、一对一专业代码讲解辅导答辩、模拟答辩演练、和理解代码逻辑思路。 特色服务内容:答辩必过班 (全程一对一技术交流,帮助大家顺利完成答辩,小白必选) 全网粉丝50W+,累计帮助2000+完成优秀毕设 🍅文末获取源码🍅 感兴趣的可以先收藏起来,还有大家在毕设选题,

By Ne0inhk
C++ 智能指针完全指南:原理、用法与避坑实战(从 RAII 到循环引用)

C++ 智能指针完全指南:原理、用法与避坑实战(从 RAII 到循环引用)

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 智能指针的核心:RAII 设计思想 * 1.1 为什么需要智能指针? * 1.2 RAII:智能指针的设计灵魂 * 二. C++ 标准库智能指针:用法与场景 * 2.1 unique_ptr:独占式智能指针(推荐优先使用) * 2.2 shared_ptr:共享式智能指针(支持拷贝,重点了解) * 2.3 weak_ptr:弱引用智能指针(解决循环引用) * 2.3.1

By Ne0inhk