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

OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

OpenClaw 搭建全流程实战:从 0 部署到可控 AI Agent(附避坑与安全建议)

近几个月,「AI Agent」成为技术圈的高频词,但大多数人停留在 Demo、插件和概念层。 真正能跑在本地 / 服务器、拥有真实权限、能持续执行任务的 Agent 并不多。 OpenClaw,正是目前少数几个工程完整、可部署、可二次开发的开源 AI Agent 框架之一。 这篇文章不讲愿景、不画饼,只讲怎么搭、怎么跑、怎么不翻车。 一、OpenClaw 到底是什么?先说清楚定位 一句话说明白: OpenClaw 是一个可部署在本地或服务器上的开源 AI Agent 框架,具备 Gateway(通信)、Dashboard(控制台)和 Skills(能力插件)三大核心模块。 和 ChatGPT / 插件的本质区别在于: 对比项普通 AI 工具OpenClaw运行位置云端本地

By Ne0inhk
人工智能:大模型高效推理与部署技术实战

人工智能:大模型高效推理与部署技术实战

人工智能:大模型高效推理与部署技术实战 1.1 本章学习目标与重点 💡 学习目标:掌握大语言模型推理与部署的核心技术,理解模型量化、推理加速、服务化部署的原理,能够完成开源大模型的高性能生产级部署。 💡 学习重点:精通INT4/INT8量化技术的应用,掌握vLLM等高性能推理框架的使用方法,学会搭建高并发的大模型API服务。 1.2 大模型推理部署的核心挑战 1.2.1 大模型推理的痛点分析 💡 预训练大模型通常具备数十亿甚至上百亿的参数量,直接进行推理会面临显存占用高、推理速度慢、并发能力弱三大核心问题。 * 显存占用高:以LLaMA-2-7B模型为例,FP16精度下显存占用约14GB,单张消费级显卡难以承载;而70B模型FP16精度显存占用更是超过140GB,普通硬件完全无法运行。 * 推理速度慢:自回归生成的特性导致模型需要逐token计算,单条长文本生成可能需要数十秒,无法满足实时应用需求。 * 并发能力弱:传统推理方式下,单卡同时处理的请求数极少,高并发场景下会出现严重的排队和延迟问题。 这些问题直接制约了大模型从实验室走向实际生产环境,因此高效

By Ne0inhk
医疗AI场景下算法编程的深度解析(2026新生培训讲稿)(八)

医疗AI场景下算法编程的深度解析(2026新生培训讲稿)(八)

第15章 模型融合与集成策略 在机器学习竞赛和实际应用中,模型融合(Model Ensemble)是提升预测性能的利器。通过组合多个不同的基模型,集成策略能够综合各个模型的优势,抵消单个模型的偏差和方差,从而获得比任何单一模型更稳定、更准确的预测结果。在医疗AI领域,模型融合同样具有重要价值——面对复杂多模态的医疗数据,单一模型往往难以全面捕捉所有信息,而融合多个异质模型可以提升诊断的鲁棒性和准确性。本章将从集成学习的基本思想出发,系统介绍常见的模型融合方法,包括投票法、平均法、Stacking、Blending等,并通过实战案例展示如何构建融合模型来提升疾病预测性能。 15.1 集成学习的基本思想 集成学习(Ensemble Learning)的核心思想是“三个臭皮匠,顶个诸葛亮”——通过结合多个学习器来完成学习任务,通常可以获得比单一学习器更优越的泛化性能。根据个体学习器的生成方式,集成学习主要分为两大类: * Bagging:并行训练多个独立的基学习器,然后通过平均或投票进行结合。典型代表是随机森林。Bagging主要降低方差。 * Boosting:串行训练基学习

By Ne0inhk
Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力

Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 huggingface_client 的鸿蒙化适配指南 - 连接全球最大 AI 开源社区、助力鸿蒙应用构建云端一体的大模型推理能力 前言 在 OpenHarmony 鸿蒙应用全场景智能化的今天,AI 模型的获取与推理能力已成为应用的核心竞争力。如果你希望在鸿蒙应用中集成最前沿的文本生成、图像识别或语音转写功能,而又不想从零开始训练模型,那么 Hugging Face Hub 正是你不可或缺的“AI 军火库”。huggingface_client 作为一个专为 Dart/Flutter 设计的官方级客户端,提供了对 Hugging Face API 的深度封装。本文将指导你如何在鸿蒙端利用此库轻松调取全球顶尖的开源 AI 算力。 一、原原理分析 / 概念介绍 1.1

By Ne0inhk