Linux 进程间通信之管道基础解析 —— 匿名管道的原理与实现

Linux 进程间通信之管道基础解析 —— 匿名管道的原理与实现
在这里插入图片描述

🔥草莓熊Lotso:个人主页
❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》
✨生活是默默的坚持,毅力是永久的享受!


🎬 博主简介:

在这里插入图片描述

文章目录


前言:

在 Linux 系统中,进程是资源分配的基本单位,各个进程拥有独立的地址空间,进程间的隔离性让数据无法直接互通,而进程间通信(IPC)就是打破这种隔离、实现进程数据交互和协同工作的核心技术。管道作为 Unix 系统中最古老的 IPC 方式,也是 Linux 下最基础、最常用的进程间通信手段,其设计贴合 Linux一切皆文件的核心思想,简单易用且能满足亲缘进程间的通信需求。本文将从管道的基础概念出发,深入解析匿名管道的创建、工作原理,从文件描述符和内核视角带你吃透匿名管道的底层逻辑。

声明:看到这里博主就准备更换一下自己的配置了,首先是语言主要会用cpp了,然后云服务器从Centos到Ubuntu,文本编辑器选择的vscode和远端进行连接使用。后续要是有时间的话博主会出一期关于配置切换的文章然后链接放在这里。大家可以自己先去查查怎么做,其实也是很简单的,并不复杂。


一. 进程间通信基础认知

在学习管道之前,我们需要先明确进程间通信的核心目的和分类,建立对 IPC 技术的整体认知,这能帮助我们更好地理解管道的设计初衷和应用场景。

1.1 进程间通信的核心目的

进程间通信的本质是实现进程间的数据交互、资源共享和事件协同,具体可分为四个方面:

  • 数据传输:一个进程将自身数据发送给另一个进程,是最基础的 IPC 需求;
  • 资源共享:多个进程共享同一份系统资源(如文件、内存),提高资源利用率;
  • 通知事件:进程向其他进程发送事件通知,如子进程退出时通知父进程、进程完成任务后通知调度进程;
  • 进程控制:一个进程对另一个进程进行执行控制,如调试进程拦截目标进程的异常和陷入,实时获取其状态。
在这里插入图片描述

1.2 进程间通信的发展与分类

Linux 的 IPC 技术从 Unix 继承并不断发展,整体可分为三大类,管道是其中最基础的一类:

  • 管道:包括 匿名管道(pipe)命名管道(FIFO),是最基础的 IPC 方式,基于文件系统实现;
  • System V IPC:包括共享内存、消息队列、信号量,由 System V 系统引入,基于内核的 IPC 资源管理实现;
  • POSIX IPC:遵循 POSIX 标准的 IPC 方式,是对 System V IPC 的改进,包括 POSIX 共享内存、消息队列、信号量等。

管道作为最原始的 IPC 方式,虽然功能简单,但却是理解 Linux 进程间通信和文件系统的关键,也是实现其他复杂 IPC 的基础。

在这里插入图片描述

二. 管道的基础概念

2.1 管道的定义

管道是一种半双工的数据流通信方式,本质是内核中的一块缓冲区,它将一个进程的标准输出与另一个进程的标准输入相连,形成一条单向的数据流通道。我们可以把管道理解为进程间的 “一根水管”,数据从一端写入,从另一端读出,实现单向的通信。

在 Linux 命令行中,我们经常使用的管道符|就是管道的典型应用,例如who | wc -l

  • who进程的标准输出被重定向到管道的写端;
  • wc -l进程的标准输入被重定向到管道的读端;
    内核中的管道缓冲区作为中间介质,完成两个进程间的数据传递。

我们还可以使用下图中这样的实验来看一下管道

在这里插入图片描述
  • 从图中我们可以看出最后他们三个指令的父进程都是bash的,他们之间是具有血缘关系的进程

2.2 管道的核心特性(最后总结部分的图片里更全点,可以着重看那个)

管道的设计贴合 Linux一切皆文件的思想,其核心特性可总结为(在文章的最后我们还会有更全面点的总结,这里可以简单看下):

  • 半双工通信:数据只能沿一个方向流动,若需双向通信,需创建两个管道;
  • 基于缓冲区:管道的实质是内核缓冲区,数据写入后暂存于内核,直到被另一个进程读取;
  • 文件式操作:管道通过文件描述符操作,读写接口与文件一致(read/write),符合 Linux 文件操作规范;
  • 亲缘进程专属:匿名管道仅支持具有共同祖先的亲缘进程(父进程与子进程、兄弟进程)间通信。

引入

关于匿名管道的两个初步理解图,可以看完再继续往下细节的学习

在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

三. 匿名管道的创建与 API

匿名管道是最基础的管道类型,通过系统调用pipe创建,其核心 API 简单且易用,是实现亲缘进程间通信的首选。

3.1 匿名管道的创建函数

#include<unistd.h>intpipe(int pipefd[2]);

函数参数

  • pipefd:整型数组,是输出型参数,用于保存管道的读、写文件描述符:
    • pipefd[0]:管道的读端,仅用于读取管道中的数据;
    • pipefd[1]:管道的写端,仅用于向管道中写入数据。

返回值

  • 成功:返回 0;
  • 失败:返回 - 1,并设置errno表示错误原因。

注意:调用pipe函数的进程会同时持有管道的读端和写端,若要实现两个进程间的单向通信,需要在进程创建后关闭各自无用的文件描述符,避免数据读写异常

在这里插入图片描述

3.2 匿名管道的简单使用示例

下面的示例实现了一个基础的匿名管道通信:从键盘读取数据写入管道,再从管道读取数据输出到屏幕,直观展示管道的读写操作。

#include<cstdio>#include<cstdlib>#include<cstring>#include<unistd.h>intmain(){int fds[2];char buf[100];int len;if(pipe(fds)==-1){ std::perror("make pipe"); std::exit(1);}while(std::fgets(buf,100,stdin)){ len = std::strlen(buf);if(write(fds[1], buf, len)!= len){ std::perror("write to pipe");break;} std::memset(buf,0x00,sizeof(buf));if((len =read(fds[0], buf,100))==-1){ std::perror("read from pipe");break;}if(write(1, buf, len)!= len){ std::perror("write to stdout");break;}}return0;}

该示例中,进程自身同时完成管道的写和读操作,虽然未实现跨进程通信,但清晰展示了管道的基本读写流程:通过fd[1]写通过fd[0]读,操作接口与普通文件完全一致。


四. 基于 fork 的匿名管道跨进程通信

匿名管道本身由单个进程创建,要实现跨进程通信,需要借助fork函数创建子进程 —— 子进程会继承父进程的文件描述符表,从而与父进程共享同一个管道的读、写端,这是匿名管道实现亲缘进程通信的核心原理。

在这里插入图片描述

4.1 fork 共享管道的核心原理

fork函数创建的子进程会复制父进程的文件描述符表,包括父进程创建的管道读、写端文件描述符,因此父子进程会共享同一个内核管道缓冲区,实现数据互通。其核心步骤分为三步:

  • 父进程创建管道:父进程调用pipe创建管道,持有fd[0](读)和fd[1](写)两个文件描述符;
  • 父进程 fork 创建子进程:子进程继承父进程的文件描述符表,同样持有管道的fd[0]和fd[1];
  • 关闭无用的文件描述符:根据通信方向,父、子进程分别关闭无用的读 / 写端,实现单向通信。

例如要实现父进程读、子进程写,则:

  • 父进程关闭写端fd[1],仅保留读端fd[0]
  • 子进程关闭读端fd[0],仅保留写端fd[1]
  • 注意下面图中的是父写子读,不过基本逻辑都一样
在这里插入图片描述

4.2 从文件描述符视角理解管道通信

从文件描述符的角度,我们可以更清晰地看到父子进程共享管道的过程,以父读子写为例:

✅️ 步骤 1:父进程创建管道
父进程的文件描述符表中,0、1、2 分别为标准输入、标准输出、标准错误,pipe创建的管道分配到 3(读端fd[0])和 4(写端fd[1])。

父进程:0(tty)1(tty)2(tty)3(pipe读)4(pipe写)

✅️ 步骤 2:父进程 fork 创建子进程
子进程复制父进程的文件描述符表,此时父子进程的文件描述符 3、4 均指向同一个内核管道缓冲区。

父进程:0(tty)1(tty)2(tty)3(pipe读)4(pipe写) 子进程:0(tty)1(tty)2(tty)3(pipe读)4(pipe写)

核心关键点:父子进程的文件描述符指向同一个内核管道缓冲区,这是进程间能通过管道通信的根本原因;关闭无用描述符则是为了保证通信的单向性,避免出现数据读写的混乱。

✅️ 步骤 3:关闭无用文件描述符
父进程关闭写端 4,子进程关闭读端 3,此时管道形成单向的 “子写父读” 通道,数据只能从子进程写入,父进程读出。

父进程:0(tty)1(tty)2(tty)3(pipe读)- 子进程:0(tty)1(tty)2(tty)-4(pipe写)

核心关键点:父子进程的文件描述符指向同一个内核管道缓冲区,这是进程间能通过管道通信的根本原因;关闭无用描述符则是为了保证通信的单向性,避免出现数据读写的混乱。

4.3 子写父读的完整实战示例以及四个场景分析(场景分析挺重要的)

下面的示例实现了子进程向管道写入字符串,父进程从管道读取并打印的功能,是 “子写父读” 的标准实现:

#include<iostream>#include<string>#include<unistd.h>// 子进程 wvoidWriteData(int wfd){int cnt =1; pid_t id =getpid();while(true){sleep(1); std::string message ="hello father process, "; message +="cnt: "+ std::to_string(cnt++)+", my pid is: "+ std::to_string(id);write(wfd, message.c_str(), message.size());}}// 父进程:rvoidReadData(int rfd){char inbuffer[1024];while(true){ ssize_t n =read(rfd, inbuffer,sizeof(inbuffer)-1);if(n >0){sleep(5); inbuffer[n]='\0'; std::cout <<getpid()<<"# "<< inbuffer << std::endl;}}}intmain(){// 1. 创建管道成功int pipefd[2]={0};int n =pipe(pipefd);(void)n;// 2. 创建子进程 pid_t id =fork();if(id ==0){// 3.形成单向通信的信道// 子进程: wclose(pipefd[0]);// 关掉我不用的这个读WriteData(pipefd[1]);close(pipefd[1]);// 可以关掉exit(0);}else{// 3.形成单向通信的信道// 父进程: rclose(pipefd[1]);// 关掉我不用的这个写ReadData(pipefd[0]);close(pipefd[0]);// 可以关掉}// 0->read 1->wirte// 0->嘴巴->读 1->笔->写// std::cout << "pipefd[0]: " << pipefd[0] << std::endl;// std::cout << "pipefd[1]: " << pipefd[1] << std::endl;return0;}
  • 通过对上述案例进行一定程度上的修改,有一想4种情况,大家注意看一下,也可以根据我的截图自己改了去试一下
在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
在这里插入图片描述

五. 从内核视角看管道的本质

从文件描述符视角,我们理解了管道的使用流程,而从内核视角,我们能看透管道的底层实现 —— 管道的本质是内核中的一块缓冲区,由两个file结构体指向同一个inode,贴合 Linux “一切皆文件” 的设计思想。

5.1 管道的内核数据结构

在 Linux 内核中,管道的底层实现涉及三个核心数据结构:

  • file结构体:进程的文件描述符表中的每个项都指向一个file结构体,记录文件的操作方式、当前偏移量等信息;
  • inode结构体:用于描述文件的物理属性,管道的inode中保存了管道缓冲区的地址、大小、读写位置等核心信息;
  • 管道缓冲区:内核中的一块连续内存,是管道实际存储数据的地方。

对于匿名管道,父子进程的fd[0]fd[1]会分别指向不同的file结构体,但这两个file结构体最终会指向同一个inode结构体,而该inode指向内核中的管道缓冲区

在这里插入图片描述

5.2 管道的内核实现逻辑

当进程对管道执行read/write操作时,内核的处理逻辑如下:

  • 写操作write(fd[1], data, len):内核将数据从进程地址空间复制到管道缓冲区,并更新inode中的写位置;
  • 读操作read(fd[0], buf, len):内核将管道缓冲区中的数据复制到进程地址空间,并更新inode中的读位置;
  • 缓冲区同步:内核会保证管道缓冲区的读写同步,若缓冲区为空,读操作会阻塞;若缓冲区满,写操作会阻塞。这个上面也有分析到一点。

简单来说,管道的读写操作本质是进程地址空间与内核缓冲区之间的数据拷贝,而两个进程共享同一个内核缓冲区,就实现了数据的跨进程传递。

  • 补充:读写规则的一些了解,可以简单看看
在这里插入图片描述

5.3 管道与普通文件的异同

管道的操作接口与普通文件一致,但二者在底层实现和使用上有明显区别,核心对比如下:

特性管道普通文件
存储介质内核缓冲区磁盘 / 块设备
生命周期随进程(进程退出释放)随文件系统(需手动删除)
数据读写流式读写,不可随机访问支持随机访问(lseek)
共享方式仅亲缘进程通过文件描述符共享所有进程可通过路径 / 文件描述符共享
数据持久化不持久化(读出即删除)持久化(数据保存在磁盘)

但二者的核心共性是都遵循 Linux 的文件操作模型,通过文件描述符file结构体、inode结构体实现操作,这也是管道能复用文件读写接口的根本原因。


六. 核心要点总结(含管道5个特点总结图)

本文从进程间通信的基础出发,详细解析了 Linux 匿名管道的核心概念、创建 API、基于 fork 的跨进程通信实现,并从文件描述符内核两个视角深入剖析了匿名管道的底层逻辑,核心要点可总结为:

  • 管道是 Linux 最基础的 IPC 方式,本质是内核中的一块缓冲区,贴合 “一切皆文件” 的设计思想,通过read/write接口操作;
  • 匿名管道通过pipe函数创建,返回读、写两个文件描述符,需借助fork实现亲缘进程间通信,核心是子进程继承父进程的文件描述符表,共享同一个内核管道缓冲区;
  • 匿名管道通信的标准流程是:创管道→fork 子进程→关闭无用文件描述符→读写通信→关闭描述符,关闭无用描述符是保证单向通信的关键;
  • 从文件描述符视角,父子进程的文件描述符指向同一个内核管道缓冲区;从内核视角,管道是由两个file结构体指向同一个inode的内核缓冲区,读写操作是进程与内核缓冲区之间的数据拷贝;
  • 匿名管道是半双工的,仅支持亲缘进程间的单向通信,若需双向通信需创建两个管道,且其生命周期随进程,数据不持久化。
在这里插入图片描述

结尾:

🍓 我是草莓熊 Lotso!若这篇技术干货帮你打通了学习中的卡点: 👀 【关注】跟我一起深耕技术领域,从基础到进阶,见证每一次成长 ❤️ 【点赞】让优质内容被更多人看见,让知识传递更有力量 ⭐ 【收藏】把核心知识点、实战技巧存好,需要时直接查、随时用 💬 【评论】分享你的经验或疑问(比如曾踩过的技术坑?),一起交流避坑 🗳️ 【投票】用你的选择助力社区内容方向,告诉大家哪个技术点最该重点拆解 技术之路难免有困惑,但同行的人会让前进更有方向~愿我们都能在自己专注的领域里,一步步靠近心中的技术目标! 

结语:匿名管道作为最原始的 IPC 方式,虽然功能有限,但却是理解 Linux 进程间通信、文件系统和内核机制的关键。后面的文章中,我们将继续深入讲解管道的读写规则、命名管道(FIFO)的实现,以及管道在进程池中的实际应用,带你进一步吃透 Linux 管道技术。创作不易,觉得本文有帮助的话,欢迎点赞、收藏、关注三连~ 后续会持续更新 Linux 进程间通信的其他核心技术(共享内存、消息队列、信号量等),带你从底层吃透 Linux IPC。

✨把这些内容吃透超牛的!放松下吧✨ʕ˘ᴥ˘ʔづきらど

Read more

大公博创DGB收官2026WDS沙特世界防务展 签约卡塔尔Dynasty Group和沙特DTI深化中东布局,全频段反无人机技术引发海外行业关注

利雅得,沙特阿拉伯 2 月12日–2026年沙特防务展圆满落幕,全球电磁空间安全解决方案领军企业、低空空域安全领域先锋大公博创DGB (DG.Broadtrum) 在本届展会上迎来多重突破:不仅携“全频段、全时域、全地域”要地安防综合解决方案及三款旗舰产品重磅亮相,凭借军工级技术实力成为低空安防领域的关注焦点,更在展会期间接连斩获重磅合作——2月10日与卡塔尔本土标杆企业Dynasty Group签署战略合作备忘录(MoU),2月12日展会收官之际,再与沙特本土先进无人机技术领军企业Drone Tech International(DTI)正式达成战略合作。凭借亮眼的技术展示与深度的本地化合作布局,大公博创DGB获得沙特本土及众多海外主流媒体的现场采访与高度关注,成为本届展会中中国高端安防技术出海的典型代表。此举标志着大公博创DGB在中东市场的布局实现跨越式深化,以“技术输出+本地化协同”的双轮驱动模式,持续为海湾国家防务自主建设与基础设施安全升级注入中国力量,也为中东海湾地区低空空域安全生态构建奠定了重要合作基础。 亮相沙特防务展:全频段反无人机技术成焦点,引全球媒体聚焦 在本届

By Ne0inhk

Git-RSCLIP效果展示:1000万数据训练的遥感AI有多强

Git-RSCLIP效果展示:1000万数据训练的遥感AI有多强 遥感图像里藏着什么?一条蜿蜒的河流、一片整齐的稻田、一座繁忙的机场,还是城市扩张留下的边界线?过去,要从卫星图或航拍图中识别这些地物,得靠专业人员肉眼判读,或者训练专用分类模型——耗时、费力、门槛高。而今天,一个不用训练、上传即用、输入文字就能“看懂”遥感图的AI,已经站在你面前。 它叫 Git-RSCLIP,不是普通CLIP的简单迁移,而是北航团队专为遥感领域打磨的视觉语言模型。它在1000万对遥感图文数据上完成预训练,不是泛泛而谈的“多模态”,而是真正理解“农田”和“裸地”的光谱差异、“机场跑道”和“高速公路”的几何特征、“森林冠层”和“城市绿地”的纹理区别。 这篇文章不讲架构推导,不列参数表格,也不堆砌技术术语。我们直接打开界面、上传图片、输入描述、看结果——用10个真实测试案例,带你亲眼见证:

By Ne0inhk
Flutter 三方库 shelf_modular 的鸿蒙化适配指南 - 掌控服务器路由资产、精密模块治理实战、鸿蒙级服务端专家

Flutter 三方库 shelf_modular 的鸿蒙化适配指南 - 掌控服务器路由资产、精密模块治理实战、鸿蒙级服务端专家

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 shelf_modular 的鸿蒙化适配指南 - 掌控服务器路由资产、精密模块治理实战、鸿蒙级服务端专家 在鸿蒙跨平台应用执行高级服务端管理与多维 Shelf 路由资产指控(如构建一个支持全场景秒级交互的鸿蒙大型全量后端服务中枢、处理海量 API Route Payloads 的语义认领或是实现一个具备极致指控能力的资产管理后台路由审计中心)时,如果仅仅依赖官方的基础 Shelf 处理器或者是极其繁琐的手动路由映射,极易在处理“由于模块嵌套导致的资产认领偏移”、“高频服务请求下的认领假死”或“由于多语言环境导致的符号解析冲突死结”时陷入研发代码服务端逻辑崩溃死循环。如果你追求的是一种完全对齐现代模块化标准、支持全量高度可定制路由(Modular-driven Backend)且具备极致指控确定性的方案。今天我们要深度解析的 shelf_modular——一个专注于解决“服务端资产标准化认领与模块化解耦”痛点的顶级工具库,正是帮你打造“鸿蒙超

By Ne0inhk
ICLR 2026中稿工作VLASER: 究竟哪些多模态能力和数据对提升机器人的控制表现最关键?

ICLR 2026中稿工作VLASER: 究竟哪些多模态能力和数据对提升机器人的控制表现最关键?

一、背景和研究动机 在具身智能(Embodied AI)的浪潮中,研究界致力于将强大的视觉-语言模型(VLM)转化为具备机器人操控能力的 Vision-Language-Action (VLA) 模型 。然而,这一转化过程面临着一道巨大的“鸿沟”:上游 VLM 通常依托海量互联网数据预训练,拥有卓越的通用推理能力;而下游 VLA 却需要在具体的物理环境中实现精准的动作控制 。 目前的现状是:即便 VLM 的通用推理能力很强,在迁移至机器人控制任务时,效果往往不如人意 。这引发了一个核心问题:究竟哪些多模态能力和数据对提升机器人的控制表现最关键? 是堆砌更多的通用问答数据,还是专注于特定的域内(机器人第一视角)的多模态推理数据 ? 为解答这一疑问,来自中国科学技术大学、上海人工智能实验室、上海交通大学等机构的研究团队,在 ICLR 2026 发表了最新成果:Vlaser (Vision-Language-Action Model with Synergistic Embodied Reasoning) 。Vlaser

By Ne0inhk