【Linux系统化学习】深入理解匿名管道(pipe)和命名管道(fifo)
目录
进程间通信
进程间通信目的
进程间通信的方式
管道
System V IPC(本地通信)
POSIX IPC(网络通信)
管道
什么是管道
匿名管道
匿名管道的创建
匿名管道的使用
匿名管道的四种情况
匿名管道的五种特性
命名管道
指令级的命名管道
代码级的命名管道
读端
写端
匿名管道与命名管道的区别
进程间通信
从Linux这个专栏开始我们已经系统学习了两大块内容——进程和文件系统。但是内存中的文件离不开进程;因此可见进程的重要性,但是我们只是对单一的一个进程进行研究。可实际我们总能发现需要将一个程序的输出交给另一个程序进行处理,这就是进程间的通信;但是进程具有独立性,我们不可以将一个进程的数据拷贝给另一个进程,因此两个进程通信必须含有一个中间媒介用于音系交流。
进程间通信的本质就是:让不同的进程先看到同一份资源。
进程间通信目的
- 数据传输:一个进程需要将它的数据发送给另一个进程
- 资源共享:多个进程之间共享同样的资源。
- 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
- 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程间通信的方式
管道
- 匿名管道pipe
- 命名管道FIFO
System V IPC(本地通信)
- System V 消息队列
- System V 共享内存
- System V 信号量
POSIX IPC(网络通信)
- 消息队列
- 共享内存
- 信号量
- 互斥量
- 条件变量
- 读写锁
管道
什么是管道
- 管道是Unix中最古老的进程间通信的形式。
- 我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
注意:是因为含有一种数据的传送方式类似管道才有的管道,而不是因为管道这个名词而建立的一种数据传送方式。(注意这两种的因果关系)
匿名管道
匿名管道的创建
#include<unistd.h>
int pipe(int fd[2]);
功能:创建一个匿名管道
参数
- fd:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端
- 返回值:成功返回0,失败返回错误码。
匿名管道的使用
#include<iostream>
#include<cstring>
#include<unistd.h>
#include<cassert>
#include<wait.h>
using namespace std;
#define MAX 1024int main()
{//第一步,建立管道int fd[2]={0};int n = pipe(fd);assert(n==0);(void)n;//第二步,创建子进程pid_t id = fork();if(id<0){perror("fork");return 1;}//子写父读//第三步:父子双方关闭不需要的fd,形成单行通道if(id==0){//childclose(fd[0]);char massage[MAX];int cnt =10;while(cnt){snprintf(massage,sizeof(massage),"I am a child , pid : %d ppid : %d cnt : %d ",getpid(),getpid(),cnt--);// w - 只向管道写入write(fd[1],massage,strlen(massage));sleep(1);}exit(0);}//fatherclose(fd[1]);char buffer[MAX];while(true){// r - 只从管道读取ssize_t n = read(fd[0],buffer,sizeof(buffer)-1);if(n>0){buffer[n]={0};cout<<getpid()<<"child say:"<<buffer<<endl;}sleep(1);}pid_t rid = waitpid(id,nullptr,0);if(rid==id){cout<<"wait success"<<endl;}return 0;
}
现象的解释:
在创建子进程前,建立管道;然后创建子进程,父进程关闭写端只做读取,子进程关闭读端只做写入;通过管道子进程写入的数据通过管道被父进程读取。
匿名管道的四种情况
1. 正常情况,如果管道没有数据了,读端必须等待,直到有数据为止(写端写入数据了)
2. 正常情况,如果管道被写满了,写端必须等待,直到有空间为止(读端读走数据)
3. 写端关闭,读端一直读取, 读端会读到read返回值为0, 表示读到文件结尾
4. 读端关闭,写端一直写入,操作系统会直接杀掉写端进程,通过想目标进程发送SIGPIPE(13)信号,终止目标进程。
匿名管道的五种特性
1. 匿名管道,可以允许具有血缘关系的进程之间进行进程间通信,常用与父子,仅限于此
2. 匿名管道,默认给读写端要提供同步机制
3. 面向字节流的
4. 管道的生命周期是随进程的
5. 管道是单向通信的,半双工通信的一种特殊情况
从文件描述符的角度来理解管道的原理
管道的原理需要结合文件系统来描述。当进程分别以读和写打开同一个文件,进程会创建PCB;PCB含有指向关于该进程打开的所有文件信息结构体(struct files_struct)的指针(struct files_struct*),这个结构体中含有一个数组,数组的每个下标代表所打开的每个文件,数组的每个元素为一个指针(struct file* fd——array[])指向被打开的文件;读和写在内存中都会加载该内存,在内存中虽然有两个文件但是这两个文件公用一个缓冲区。当fork()创建子进程的时候,会发生浅拷贝;因此子进程中的所有数据和父进程是一样的,包括指针信息。子进程中数组元素也是指向父进程所打开的读写文件,这两个文件又公用一个缓冲区;这两个文件被连个指针所指向,使用引用计数而实现需不需要文件的关闭。关闭父进程的写文件和关闭子进程的的读文件,这样子进程将信息写到缓冲区中,父进程将数据自己读取,不加载到内存中,这样就实现了管道。
命名管道
- 匿名管道的一个限制就是只能在具有共同祖先(具有血缘关系)的进程间通信
- 如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道。
- 命名管道是一种特殊类型的文件
指令级的命名管道
命名管道可以在命令行上创建,使用下面指令:
mkfifo 文件名
现象的解释:这个过程是动态的,由于动图太大不方便演示。在一个文件夹中创建了一个管道文件。echo指令进行循环写入,在另一个端口下cat命令进行读取。通过这个管道文件实现了两个不相关进程之间的通信。这个管道文件为中间媒介是实现了两个进程间的通信。
代码级的命名管道
管道也可以在程序里创建,相关函数为:
int mkfifo(const char *filename,mode_t mode)
其实命名管道就是个文件,在一个进程中创建这个文件,进行写入/读取,或者在同时在另一个文件中进行读取和写入操作,本质就是:两个不同的进程同时对同一个文件进行文件操作。这个文件就实现了进程间的通信,这个文件就是管道。
读端
在程序的一开始,直接打开这个文件;当文件不存在时创建这个管道文件,直到创建成功为止;
然后使用系统调用文件操作读函数,对文件进行读取。
#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "RW.h"bool MakeFifo()
{int n = mkfifo(FILENAME, 0666);if(n < 0){std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;return false;}std::cout << "mkfifo success... read" << std::endl;return true;
}int main()
{
Start:int rfd = open(FILENAME, O_RDONLY);if(rfd < 0){std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;if(MakeFifo()) goto Start;else return 1;}std::cout << "open fifo success..." << std::endl;char buffer[1024];while(true){ssize_t s = read(rfd, buffer, sizeof(buffer)-1);if(s > 0){buffer[s] = 0;std::cout << "Client say# " << buffer << std::endl;}else if(s == 0){std::cout << "client quit, server quit too!" << std::endl;break;}}close(rfd);std::cout << "close fifo success..." << std::endl;return 0;
}
写端
也是在程序一开始直接打开指定的管道文件,判断是否打开成功;打开成功后使用你系统调用文件操作写函数对文件进行写入。
#include <iostream>
#include <cstring>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "RW.h"int main()
{int wfd = open(FILENAME, O_WRONLY);if (wfd < 0){std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;return 1;}std::cout << "open fifo success... write" << std::endl;std::string message;while (true){std::cout << "Please Enter# ";std::getline(std::cin, message);ssize_t s = write(wfd, message.c_str(), message.size());if (s < 0){std::cerr << "errno: " << errno << ", errstring: " << strerror(errno) << std::endl;break;}}close(wfd);std::cout << "close fifo success..." << std::endl;return 0;
}
现象的解释:当我们同时在两个窗口运行这两个可执行程序时,在写端写入回车成功后;将数据写到管道文件中,当读端检测到管道文件中数据时会将这条消息读取。其实这个过程是同步进行的,由于这里动图太大,不方便演示。
从底层来看命名管道的原理和匿名管道的原理基本相同这里就不过多赘述了。
匿名管道与命名管道的区别
- 匿名管道由pipe函数创建并打开。
- 命名管道由mkfifo函数创建,打开用open
- FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的意义。
今天对Linux下管道实现进程间通信的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!!
相关文章:

【Linux系统化学习】深入理解匿名管道(pipe)和命名管道(fifo)
目录 进程间通信 进程间通信目的 进程间通信的方式 管道 System V IPC(本地通信) POSIX IPC(网络通信) 管道 什么是管道 匿名管道 匿名管道的创建 匿名管道的使用 匿名管道的四种情况 匿名管道的五种特性 命名管道 …...
信息学奥赛一本通1209:分数求和
1209:分数求和 时间限制: 1000 ms 内存限制: 65536 KB 提交数: 19111 通过数: 10647 【题目描述】 输入n个分数并对他们求和,并用最简形式表示。所谓最简形式是指:分子分母的最大公约数为11;若最终结果的分母为11&am…...

LabVIEW储氢材料循环寿命测试系统
LabVIEW储氢材料循环寿命测试系统 随着氢能技术的发展,固态储氢技术因其高密度和安全性成为研究热点。储氢材料的循环寿命是衡量其工程应用的关键。然而,传统的循环寿命测试设备存在成本高、测试效率低、数据处理复杂等问题。设计了一种基于LabVIEW软件…...
Unity3D 框架如何搭建基于纯Lua的U框架与开发模式详解
前言 Unity3D 是一款非常流行的游戏开发引擎,它支持C#、JavaScript和Boo等多种脚本语言。而Lua语言作为一种轻量级的脚本语言,也在游戏开发中得到了广泛应用。本文将介绍如何在Unity3D框架中搭建基于纯Lua的U框架,并详细讲解其开发模式。 对…...

Linux常见指令(2)
目录 1、tar指令 ! 2、bc指令 3、uname 4、重要热键 5、关机 1、tar指令 ! 功能:压缩/解压缩文件或目录,类似zip 我们先来看一下我们的文件即目录,接下来我们输入指令: tar -czf test.tgz test 压缩 -c …...
【C++】封装
1.封装的意义 封装是C面向对象三大特性之一 实例化(通过一个类 创建一个对象的过程) 类中的属性和行为 我们统一称为 成员 属性 成员属性 成员变量 行为 成员函数 成员方法 封装的意义: 1.将属性和行为作为一个整体,表现生活中的事…...

Maxwell安装部署
1 Maxwell输出格式 database:变更数据所属的数据库table:变更数据所属的表type:数据变更类型ts:数据变更发生的时间xid:事务idcommit:事务提交标志,可用于重新组装事务data:对于inse…...

说一下JVM类加载机制?
Java中的所有类,都需要由类加载器装载到JVM中才能运行。类加载器本身也是一个类,而它的工作就是把class文件从硬盘读取到内存中。 在写程序的时候,我们几乎不需要关心类的加载,因为这些都是隐式装载的,除非我们有特殊…...

解决SpringAMQP工作队列模型程序报错:WARN 48068:Failed to declare queue: simple.queue
这里写目录标题 1.运行环境2.报错信息3.解决方案4.查看解决之后的效果 1.运行环境 使用docker运行了RabbitMQ的服务器: 在idea中导入springAMQP的jar包,分别编写了子模块生产者publisher,消费者consumer: 1.在publisher中运行测试…...

mysql在服务器中的主从复制Linux下
mysql在服务器中的主从复制Linux下 为什么要进行主从复制主从复制的原理主从复制执行流程操作步骤主库创建从库创建 测试 为什么要进行主从复制 在业务中通常会有情况,在sql执行时,将表锁住,导致不能进行查询,这样就会影响业务的…...

QT-Day2
思维导图 作业 使用手动连接,将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中,在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中,在槽函数中判断ui界面上输入的账号是否为"admin"&#x…...

流量分析——陇剑杯 2021【签到、jwt】
目录 签到1、攻击者正在进行的可能是什么协议的网络攻击 jwt1、该网站使用了______认证方式。前置知识:解: 2、黑客绕过验证使用的jwt中,id和username是3、黑客获取webshell之后,权限是什么4、黑客上传的恶意文件文件名是5、黑客在…...

Java并发基础:原子类之AtomicIntegerFieldUpdater全面解析
本文概要 AtomicIntegerFieldUpdater类提供了一种高效、简洁的方式来原子性地更新对象的volatile字段,无需使用重量级的锁机制,它通过基于反射的API实现了细粒度的并发控制,提升了多线程环境下的性能表现。 AtomicIntegerFieldUpdater核心概…...

普中51单片机学习(串口通信)
串口通信 原理 计算机通信是将计算机技术和通信技术的相结合,完成计算机与外部设备或计算机与计算机之间的信息交换 。可以分为两大类:并行通信与串行通信。并行通信通常是将数据字节的各位用多条数据线同时进行传送 。控制简单、传输速度快࿱…...

【ArcGIS】利用高程进行坡度分析
在ArcGIS中利用高程进行坡度分析 坡度ArcGIS实操参考 坡度 坡度是地表单元陡缓的程度,通常把坡面的垂直高度和水平距离的比值称为坡度。 坡度的表示方法有百分比法、度数法、密位法和分数法四种,其中以百分比法和度数法较为常用。 (1&#…...
递归读取文件夹下的所有文件
水一篇文章 🐶 代码 package file;import org.apache.commons.lang3.StringUtils; import org.junit.Test;import java.io.File; import java.util.Objects;/*** FlattenDirFiles** author allens* date 2024/2/19*/ public class FlattenDirFiles {// 文件数量pri…...
phpspreadsheet导出数据和图片到excel
仅作记录,废话不多说 前提是已经安装了phpspreadsheet ( composer require phpoffice/phpspreadsheet ) 一、 数据拼装,调用excel类 <?php /*** 电子台账* Date: 2023/4/20* Time: 17:28*/namespace app\store\controlle…...
Seata的 TCC 模式
目录 概述 使用 依赖与配置 代码 概述 TCC 模式是一种侵入式的分布式事务解决方案,它不依赖于数据库的事务,而是要求开发者自定义完成 预提交、提交、回滚的方法逻辑。因此,它是一个种偏 复杂、灵活、有侵入性 的分布式事务处理方案。 De…...
Vue全局指令防止重复点击(等待请求)
继《vue之全局请求loading》之后,总觉得全局loading有时候不太…友好,所以总想将loading加到被点击的元素上面,于是乎就想到了点击事件与请求方法相关联,本想重写组件的click方法,但是这样对组件的影响太大,…...

数据库索引面试的相关问题
查看索引的执行计划 索引失效的情况 1、索引列上做了计算,函数,类型转换等操作。索引失效是因为查询过程需要扫描整个索引并回表。代价高于直接全表扫描。 Like匹配使用了前缀匹配符“%abc” 字符串不加引号导致类型转换。 原因: 常见索…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...

(十)学生端搭建
本次旨在将之前的已完成的部分功能进行拼装到学生端,同时完善学生端的构建。本次工作主要包括: 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...

对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...