【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即可):
相关推荐
橘子真甜~39 分钟前
C/C++ Linux网络编程15 - 网络层IP协议
linux·网络·c++·网络协议·tcp/ip·计算机网络·网络层
拾贰_C2 小时前
【Linux | Windows | Terminal Command】 Linux---grep | Windows--- findstr
linux·运维·服务器
阿华hhh2 小时前
Linux系统编程(标准io)
linux·开发语言·c++
虹科网络安全3 小时前
艾体宝洞察 | 利用“隐形字符”的钓鱼邮件:传统防御为何失效,AI安全意识培训如何补上最后一道防线
运维·网络·安全
石像鬼₧魂石3 小时前
Kali Linux 网络端口深度扫描
linux·运维·网络
alengan3 小时前
linux上面写python3日志服务器
linux·运维·服务器
yBmZlQzJ4 小时前
免费内网穿透-端口转发配置介绍
运维·经验分享·docker·容器·1024程序员节
JH30734 小时前
docker 新手入门:10分钟搞定基础使用
运维·docker·容器
Rose sait4 小时前
【环境配置】Linux配置虚拟环境pytorch
linux·人工智能·python
小卒过河01044 小时前
使用apache nifi 从数据库文件表路径拉取远程文件至远程服务器目的地址
运维·服务器·数据库