【Linux】Linux进程间通信:命名管道(FIFO)的模拟实现重要知识点梳理

前言:欢迎 各位光临本博客,这里小编带你直接手撕**,文章并不复杂,愿诸君**耐其心性,忘却杂尘,道有所长!!!!

IF'Maxue个人主页
🔥 个人专栏 :
《C语言》
《C++深度学习》
《Linux》
《数据结构》
《数学建模》

⛺️生活是默默的坚持,毅力是永久的享受。不破不立!

文章目录

一、命名管道(FIFO):跨进程通信的"桥梁"

命名管道(FIFO)是Linux中一种简单的进程间通信方式,核心优势是能让无血缘关系的进程(比如两个独立的程序)互相传递数据,就像搭建了一条专用"数据管道"。

1. 命名管道的核心特性

  • 有固定文件名,存储在文件系统中(可用ls命令查看),但实际不存数据(数据在内存中)。
  • 通信时需"两端配合":必须有一个进程写(open为写模式)、一个进程读(open为读模式),否则open会阻塞(等另一端准备好)。

2. 命名管道的核心接口(代码级)

操作FIFO主要依赖3个核心接口:mkfifo(创建管道)、open/close/read/write(读写数据)、unlink(删除管道)。

(1)创建管道:mkfifo
  • 功能:在文件系统中创建一个FIFO文件,作为进程通信的"标识"。
  • 头文件 :需包含 <sys/stat.h><sys/types.h>
  • 接口参数与返回值
    • pathname:FIFO的文件名(比如"./myfifo"),进程通过这个路径找到管道。
    • mode:管道的权限(比如0664,表示所有者、组用户可读写,其他用户可读)。
    • 返回值:成功返回0,失败返回-1(比如文件已存在)。
  • 功能:删除FIFO文件,释放管道占用的资源(避免文件残留)。
  • 接口参数与返回值
    • pathname:要删除的FIFO文件名(和mkfifo的路径一致)。
    • 返回值:成功返回0,失败返回-1(比如文件不存在)。

3. 命名管道实战:Server与Client通信

FIFO通信需要两个独立程序:server.cc(读数据)和client.cc(写数据),必须同时运行才能通信。

(1)服务器端(server.cc):读数据

核心逻辑:创建管道 → 打开管道(读模式) → 读取数据 → 关闭管道 → 删除管道。

代码细节如下:

  • 创建管道 :先判断mkfifo是否成功,失败则报错(比如管道已存在)。
  • 删除管道 :一般在程序结束前调用unlink,确保资源释放(即使程序异常退出,也建议在后续处理中删除)。
  • 打开、读取、关闭管道 :用open打开管道(读模式),read循环读取数据,close关闭文件描述符。
    • 注意:open为读模式时,会阻塞等待,直到有客户端以写模式打开管道,才会返回。
(2)客户端(client.cc):写数据

核心逻辑:打开管道(写模式) → 写入数据 → 关闭管道(无需创建/删除管道,由服务器负责)。

代码细节如下:

  • 客户端只需用open打开已存在的FIFO(写模式),直接write写入数据即可;写完后close,服务器会收到read返回0的信号(表示写端关闭)。

4. 通信关键机制与问题解决

(1)open阻塞机制

FIFO的open有个"等待特性":

  • 若进程以"读模式"打开管道(O_RDONLY),会阻塞到有进程以"写模式"打开。
  • 若进程以"写模式"打开管道(O_WRONLY),会阻塞到有进程以"读模式"打开。
    效果如下:

    只有两端都打开管道,才能开始通信(写端写数据,读端立刻能读到)。
(2)写端关闭的处理

当客户端(写端)close后,服务器(读端)的read会返回0(表示"无更多数据")。此时需要在服务器代码中判断,避免无限循环读0。

修改前(无提示,读端会一直循环):

修改后(判断read返回0,提示"写端关闭"并退出):

(3)常见Bug:数据打印乱码

若直接用printf("%s", buf)打印读取的buf,可能出现乱码------因为read读取的是"二进制数据",不一定以\0结尾(C语言中%s需要\0标识字符串结束)。

Bug效果:

解决方法:手动给buf\0(注意预留\0的位置,比如buf大小1024,最多读1023字节)。

修改代码:

修改后效果(无乱码):

5. 命名管道优化:封装成类(C++)

为了简化代码、避免重复操作(比如每次都写mkfifoopenclose),可以用C++类封装FIFO的操作,核心思路是:

  • 构造函数:创建管道、打开文件描述符。
  • 析构函数:关闭文件描述符、删除管道。
  • 提供ReadWrite成员函数,供外部调用。
(1)封装头文件(Fifo.hpp)
  • 构造函数:创建管道并打开(根据"读/写角色"决定open模式)。
  • 析构函数:关闭文件描述符、删除管道(确保资源释放)。
  • 管道名优化:用宏定义统一管道路径,避免硬编码(方便修改)。
(2)封装Read/Write接口
  • 读接口:循环读取数据,自动处理\0(避免乱码)。
  • 写接口:接收字符串,直接写入管道。
(3)优化后Server与Client代码
  • 服务器端(只需创建Fifo对象,调用Read):
  • 客户端(创建Fifo对象,调用Write):

6. 命名管道扩展:实现文件拷贝

利用FIFO的通信能力,可以实现"客户端传文件、服务器存文件"的功能。核心逻辑是:

  • 客户端:打开要拷贝的文件 → 读取文件内容 → 写入FIFO。
  • 服务器:从FIFO读取内容 → 写入新文件。
    代码示例(服务器端核心逻辑):
(4)宏定义优化:简化错误处理

频繁判断"函数返回值是否为-1"会让代码冗余,可定义宏来封装"错误打印+进程退出"的逻辑。

  • 未用宏时(代码冗余):
  • 定义宏(\是C语言的"换行符续接",让宏跨多行更易读):
  • 用宏后(代码简洁,直接调用CHECK即可):
相关推荐
Crazy________3 小时前
34部署LNMP架构详细解析
linux·运维·服务器·nginx
tan180°3 小时前
Linux网络HTTP(上)(7)
linux·网络·http
小醉你真好3 小时前
17、Centos9 安装 1Panel
linux·docker·运维开发
九皇叔叔4 小时前
Linux Shell 正则表达式:从入门到实战,玩转文本匹配与处理
linux·mysql·正则表达式
lhxcc_fly4 小时前
Linux网络--6、网络层
linux·网络·ip
刺客xs4 小时前
linux GDB调试器
linux·运维·windows
ONE_SIX_MIX5 小时前
Debian 的 网络管理器 被意外卸载,修复过程
服务器·网络·debian
板鸭〈小号〉5 小时前
connect 的断线重连
运维·服务器
wydaicls5 小时前
Linux 内核伙伴系统在快速路径分配内存时,对一个内存区域(Zone)进行水位线检查和内存压力评估的关键逻辑
linux·服务器