当前位置: 首页 > news >正文

进程间通信之管道

文章目录

  • 一、管道
    • 1. 匿名管道
    • 2. 命名管道

进程具有独立性,因此进程间通信的前提是两个进程能看到同一份资源

一、管道

对于进程打开的内存文件,操作系统是以引用计数的方式创建的 file 结构体,如果让两个进程与同一个 file 结构体关联,便可以让两个进程看到同一份资源

由于 file 结构体的缓冲区只有一个,因此只能让一个进程以写的方式,另一个进程以读的方式打开同一个文件,这样便实现了单向的进程间通信
在这里插入图片描述
操作系统提供了仅在内存中创建 file 结构体(不在磁盘上创建对应的文件),这种特殊的文件称为管道文件,其中没有名字的称为 匿名管道,有名字的称为 命名管道

1. 匿名管道

进程创建匿名管道成功后,会以读和写两种方式打开管道文件,因此匿名管道通常用于父子进程的进程间通信

系统调用 pipe,头文件 unistd.h

  • int pipe(int pipefd[2]),创建匿名管道

返回值:匿名管道创建成功返回 0,出错返回 -1,并且 errno 被设置为相应的出错信息

参数:pipefd 为输出型参数,pipefd[0] 存储读端文件描述符,pipefd[1] 存储写端文件描述符

父子进程通信的步骤:

  • 父进程创建管道
    父进程以读和写两种方式打开管道文件
  • 创建子进程
    子进程会拷贝父进程的文件描述符表,因此子进程也会以读和写两种方式打开同一个管道文件
  • 父进程和子进程分别关闭自己不需要的读端或写端
    一个进程向管道中写入,另一个进程从管道中读取

子进程向匿名管道写入,父进程从匿名管道读取

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>using namespace std;int main()
{// 创建匿名管道// pipefd[0] 表示读// pipefd[1] 表示写int pipefd[2] = { 0 };if (pipe(pipefd) < 0){// 创建匿名管道失败cout << "匿名管道创建失败: " << errno << " " << strerror(errno) << endl;exit(1);}// 创建子进程pid_t id = fork();assert(id != -1);if (id == 0){// 子进程向匿名管道写入,需要关闭读close(pipefd[0]);// 开始通信int cnt = 0;char buffer[64];while (true){snprintf(buffer, sizeof(buffer), "我是子进程,这是我给你发的第 %d 个信息", ++cnt);// 向匿名管道中写入write(pipefd[1], buffer, strlen(buffer));cout << cnt << endl;// sleep(1); // 让写端慢一点// if (cnt == 3) break; // 模拟写端关闭}close(pipefd[1]);exit(0);}// 父进程从匿名管道读取,需要关闭写close(pipefd[1]);// 开始通信char buffer[64];while (true){// 从匿名管道中读取// sleep(3); // 让读端慢一点// sleep(3); break; // 模拟读端关闭int n = read(pipefd[0], buffer, sizeof(buffer) - 1);if (n > 0){        buffer[n] = '\0';cout << buffer << endl;}else if (n == 0){cout << "写端已经关闭,我读到文件结尾了" << endl;break;}else{cout << "读取错误" << endl;break;}}close(pipefd[0]);// 读端关闭,写端会收到 13 号信号 SIGPIPEint status;waitpid(id, &status, 0);cout << "子进程退出信号: " << (status & 0x7F) << endl;return 0;
}
  • 放开子进程代码中的 sleep(1),让写端慢一点,匿名管道中没有数据时,读端会等待写端写入
    在这里插入图片描述
  • 放开父进程中的 sleep(3),让读端慢一点,匿名管道中写满数据时,写端会等待读端读取
    在这里插入图片描述
  • 放开子进程中模拟写端关闭的代码,并且让写端慢一点,写端关闭后,读端读取完匿名管道中的数据后,读端会读取到文件结尾
    在这里插入图片描述
  • 放开子进程中模拟读端关闭的代码,并且让写端慢一点,读端关闭时,此时匿名管道无意义,操作系统会向写端发送 SIGPIPE 13 号信号
    在这里插入图片描述

命令行中的 | 即为匿名管道,| 会将前一个进程的标准输出重定向到匿名管道,后一个进程的标准输入重定向到匿名管道

在这里插入图片描述

通过匿名管道创建进程池:

// processpool.hpp
#include <iostream>
#include <vector>
#include <functional>
#include <cstring>
#include <cerrno>
#include <cassert>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>namespace starrycat
{class EndPoint{public:EndPoint(){}EndPoint(pid_t cid, int wfd) : _cid(cid), _wfd(wfd){}~EndPoint(){}public:pid_t _cid;int _wfd;};const int NUM = 5;class ProcessPool{using fun_t = std::function<void(int)>;public:ProcessPool(fun_t Command, int num = NUM){std::vector<int> tmpfd; // 保存子进程不需要的父进程的文件描述符for (int i = 0; i < num; ++i){// 创建管道int pipefd[2] = {0};if (pipe(pipefd) < 0){std::cout << "创建管道失败: " << errno << " " << strerror(errno) << std::endl;exit(1);}// 创建子进程int id = fork();assert(id != -1);if (id == 0){// 子进程从管道中读取,需要关闭写close(pipefd[1]);for (auto e : tmpfd) close(e); // 关闭不需要的文件描述符// 开始通信while (true){// 读取四字节整数的命令int cmd = 0;int n = read(pipefd[0], &cmd, sizeof(int));if (n == sizeof(int)){// 测试std::cout << getpid() << " ";// 执行命令Command(cmd);}else if (n == 0){// 测试std::cout << getpid() << " 读取到文件结尾了" << std::endl;break;}else{std::cout << "读取异常" << std::endl;break;}}close(pipefd[0]);exit(0);}// 父进程向管道中写入,需要关闭读close(pipefd[0]);_endPoints.push_back(EndPoint(id, pipefd[1]));tmpfd.push_back(pipefd[1]);}}ProcessPool(const ProcessPool &p) = delete;ProcessPool &operator=(const ProcessPool &p) = delete;~ProcessPool(){for (auto& e : _endPoints) {close(e._wfd);waitpid(e._cid, nullptr, 0);// 测试std::cout << "等待子进程:" << e._cid  << "成功" << std::endl;sleep(1);}}// 规定命令为四字节整数void push(int command){// 以轮训的方式调用子进程static int index = 0;write(_endPoints[index]._wfd, &command, sizeof(int));index++;index %= _endPoints.size();}private:std::vector<EndPoint> _endPoints;};
}// myctrlprocess.cc
#include "processpool.hpp"
#include <iostream>
#include <string>using namespace std;// 子进程个数
const int num = 5;void PrintLog()
{cout << "打印日志任务,正在被执行..." << endl;
}void InsertMySQL()
{cout << "执行数据库任务,正在被执行..." << endl;
}void NetQuest()
{cout << "执行网络请求任务,正在被执行..." << endl;
}void CommandError()
{cout << "任务不存在" << endl;
}void Command(int cmd)
{switch (cmd){case 0:PrintLog();break;case 1:InsertMySQL();break;case 2:NetQuest();break;default:CommandError();break;}
}int main()
{starrycat::ProcessPool ppool(Command);int command = 0;while (true){cout << "请输入命令: ";cin >> command;// 测试if (command == -1) break;ppool.push(command);sleep(1);}return 0;
}

2. 命名管道

命名管道支持两个毫不相关的进程通信,其使用和文件一样

系统调用 mkfifo,头文件 sys/types.h、sys/stat.h

  • int mkfifo(const char *pathname, mode_t mode),创建命名管道

返回值:命名管道创建成功返回 0,出错返回 -1,并且 errno 被设置为相应的出错信息

参数:

  • pathname 表示创建命名管道的路径名(如果只有文件名,则表示在进程所在的路径下创建)
  • mode 表示创建命名管道的文件权限,受 umask 影响

客户端向命名管道写入,服务端从命名管道读取

// namepipe.h
#pragma once// 命名管道文件名
const char* const fifoname = "fifo";// client.cc
#include "namepipe.h"
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>using namespace std;int main()
{// 以写方式打开命名管道int wfd = open(fifoname, O_WRONLY);if (wfd < 0){cout << "打开文件失败" << errno << " " << strerror(errno) << endl;exit(1);}// 开始通信char buffer[1024];while (true){cout << "请输入: ";char* str = fgets(buffer, sizeof(buffer), stdin);if (str == NULL){cout << "客户端退出" << endl;break;}buffer[strlen(buffer) - 1] = '\0'; // 去掉输入的回车符// 输入 quit 表示客户端退出if(strcmp(buffer, "quit") == 0) {cout << "客户端退出" << endl;break;}// 向命名管道写入write(wfd,  buffer, strlen(buffer));}close(wfd);return 0;
}// server.cc
#include "namepipe.h"
#include <iostream>
#include <cerrno>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>using namespace std;int main()
{// 创建命名管道umask(0);  // 设置进程的权限掩码if (mkfifo(fifoname, 0666) < 0){cout << "创建管道失败: " << errno << " " << strerror(errno) << endl;exit(1);}// 以读方式打开命名管道int rfd = open(fifoname, O_RDONLY);if (rfd < 0){cout << "打开文件失败" << errno << " " << strerror(errno) << endl;}// 开始通信char buffer[1024];while (true){// 从命名管道读取int n = read(rfd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = '\0';cout << "客户端: " << buffer << endl;}else if (n == 0){cout << "客户端退出了,服务端也退出" << endl;break;}else{cout << "读取异常" << endl;break;}}close(rfd); unlink(fifoname); // 删除命名管道return 0;
}

先启动 myserver,在启动 myclient

在这里插入图片描述

命名管道和匿名管道的通信特性是一样的

mkfifo 文件名
功能:创建命名管道

在这里插入图片描述

相关文章:

进程间通信之管道

文章目录 一、管道1. 匿名管道2. 命名管道 进程具有独立性&#xff0c;因此进程间通信的前提是两个进程能看到同一份资源 一、管道 对于进程打开的内存文件&#xff0c;操作系统是以引用计数的方式创建的 file 结构体&#xff0c;如果让两个进程与同一个 file 结构体关联&…...

f12 CSS网页调试_css样式被划了黑线怎么办

我的问题是这样的 class加上去了,但是样式不生效,此时可能是样式被其他样式覆盖了, 解决方案就是 给颜色后边添加一个!important...

vue-制作自动滚动效果

第一步&#xff1a;下载 可以查看官方地址chenxuan0000 npm i vue-seamless-scroll -save 第二步&#xff1a;引用 import vueSeamlessScroll from "vue-seamless-scroll";//注册components: {vueSeamlessScroll,}, 第三步&#xff1a;使用 <vue-seamless…...

[国产MCU]-BL602-开发实例-DMA数据传输

DMA数据传输 文章目录 DMA数据传输1、DMA介绍2、DMA驱动API介绍3、DMA使用示例DMA(Direct Memory Access)是一种内存存取技术,可以独立地直接读写系统内存,而不需处理器介入处理。 在同等程度的处理器负担下,DMA是一种快速的数据传送方式。 BL602的DMA控制器有4组独立专用通…...

Redis压缩列表

区分一下 3.2之前 Redis中的List有两种编码格式 一个是LINKEDLIST 一个是ZIPLIST 这个ZIPLIST就是压缩列表 3.2之后来了一个QUICKLIST QUICKLIST是ZIPLIST和LINKEDLIST的结合体 也就是说Redis中没有ZIPLIST和LINKEDLIST了 然后在Redis5.0引入了LISTPACK用来替换QUiCKLIST中的…...

【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析

【SA8295P 源码分析】62 - Android GVM Kernel 内核 make bootimage 过程分析 一、make bootimage 命令执行过程分析1.1 source buid/envsetup.sh 分析1.2 lunch msmnile_gvmq-userdebug 分析1.3 make bootimage:step 1 之 加载配置文件过程分析1.4 make bootimage:step 2 之…...

机器学习——SMO算法推导与实践

一、 硬间隔-SMO算法推导 明天再说&#xff0c;啊。。。。感觉天空明朗了很多&#xff0c;即使现在已经很晚了 还是要打开柯南&#xff0c;看看电视&#xff0c;等待天气预报所说的台风天吧&#xff01; 一时之间&#xff0c;忽然失去了用markdown语法写下推导过程的勇气。。。…...

mac的终端通过code .指令快速启动vscode

通过在vscode中安装"code"命令工具 打开vsocode&#xff0c;使用快捷键⇧⌘P&#xff0c;然后输入shell&#xff0c;会弹出来“Shell命令&#xff1a;在PATH中安装‘code’命令”浮窗&#xff0c;选择安装就可以了&#xff0c;然后就可以在终端通过code .来快速启动…...

前端系统使用iframe下载文件

需求描述 前端调用后端的接口&#xff0c;获取到文件的路径&#xff0c;并下载。 碰到的问题 页面组件存在与云端的组件库&#xff0c;使用window.open()无法满足需求&#xff08;在当前页面下载&#xff09;&#xff0c;因为路径是跨域的&#xff0c;所以决定使用iframe的方…...

RabbitMQ - 简单案例

目录 0.引用 1.Hello world 2.轮训分发消息 2.1 抽取工具类 2.2 启动两个工作线程接受消息 2.4 结果展示 3.消息应答 3.1 自动应答 3.2 手动消息应答的方法 3.3 消息自动重新入队 3.4 消息手动应答代码 4.RabbitMQ 持久化 4.1 队列如何实现持久化 4.2 消息实现持久化 5.不…...

《吐血整理》高级系列教程-吃透Fiddler抓包教程(30)-Fiddler如何抓Android7.0以上的Https包-番外篇

1.简介 通过宏哥前边几篇文章的讲解和介绍想必大家都知道android7.0以上&#xff0c;有android的机制不在信任用户证书&#xff0c;导致https协议无法抓包。除非把证书装在系统信任的证书里&#xff0c;此时手机需要root权限。但是大家都知道root手机是非常繁琐的且不安全&…...

服务器被攻击了怎么办?

服务器被攻击是无法避免的&#xff0c;但是我们能通过做好防护措施&#xff0c;提高服务器的安全性&#xff0c;降低被攻击的几率。那么当服务器已经被 攻击了&#xff0c;怎样才能降低损失呢&#xff1f;该怎样补救&#xff1f; 断开网络 全部的攻击都来自于网络&#xff0c;因…...

P1156 垃圾陷阱(背包变形)

垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方&#xff0c;它的深度为 D D D&#xff08; 2 ≤ D ≤ 100 2 \le D \le 100 2≤D≤100&#xff09;英尺。 卡门想把垃圾堆起来&#xff0c…...

[Docker实现测试部署CI/CD----构建成功后钉钉告警(7)]

目录 15、钉钉告警创建项目群&#xff0c;然后添加机器人添加机器人Jenkins 系统配置项目配置修改Jenkinsfile文件&#xff0c;添加钉钉提示信息测试 不修改Jenkinsfile文件&#xff0c;添加钉钉提示信息测试 15、钉钉告警 创建项目群&#xff0c;然后添加机器人 首先需要在钉…...

UE5 半透明覆层材质

文章目录 前言介绍示例1示例2示例3 前言 本文采用虚幻5.2.1版本演示&#xff0c;介绍半透明覆层材质&#xff08;覆层材质&#xff09;。 介绍 半透明覆层材质是 UE5.1 版本 更新的功能&#xff0c;使用半透明覆层材质&#xff0c;可以轻松的给物体表面附着一层材质。 在UE5…...

在Raspberry Pi 4上安装Ubuntu 20.04 + ROS noetic(不带显示器)

在Raspberry Pi 4上安装Ubuntu 20.04 ROS noetic&#xff08;不带显示器&#xff09; 1. 所需设备 所需设备&#xff1a; 树莓派 4 B 型 wifi microSD 卡&#xff1a;最小 32GB MicroSD 转 SD 适配器 &#xff08;可选&#xff09;显示器&#xff0c;鼠标等 2. 树莓派…...

CommStudio for .NET Crack

CommStudio for .NET Crack CommStudio for.NET使您的应用程序可以轻松地使用串行端口和调制解调器进行通信。CommStudio for.NET是一套全面的组件和可视化调试工具&#xff0c;可将远程系统和设备与visual Studio 2005和visual Studio 2008集成。开发与遗留系统和外部设备集成…...

蓝桥杯上岸考点清单 (冲刺版)!!!

大家好 我是寸铁&#x1f4aa; 真题千千万万遍&#xff0c;蓝桥省一自然现&#xff01; ✌️ 日更3000里&#xff0c;蓝桥眷顾你 &#x1f31f; 暴力出奇迹&#xff0c;打表过样例 &#x1f44a; 冲刺蓝桥杯省一模板大全来啦 &#x1f525; 蓝桥杯4月8号就要开始了 &#…...

AI一键生成短视频

AI一键生成推文短视频 阅读时长&#xff1a;10分钟 本文内容&#xff1a; 结合开源AI&#xff0c;一键生成短视频发布到常见的某音&#xff0c;某手平台&#xff0c;狠狠赚一笔 前置知识&#xff1a; 1.基本的 python 编程知识 2.chatGPT 使用过 3.stable diffution 使用过 成果…...

基于MATLAB长时间序列遥感数据分析(以MODIS数据处理为例)

MATLAB MATLAB是美国MathWorks公司出品的商业数学软件&#xff0c;用于数据分析、无线通信、深度学习、图像处理与计算机视觉、信号处理、量化金融与风险管理、机器人&#xff0c;控制系统等领域。 [1] MATLAB是matrix&laboratory两个词的组合&#xff0c;意为矩阵工厂&a…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

【JavaEE】-- HTTP

1. HTTP是什么&#xff1f; HTTP&#xff08;全称为"超文本传输协议"&#xff09;是一种应用非常广泛的应用层协议&#xff0c;HTTP是基于TCP协议的一种应用层协议。 应用层协议&#xff1a;是计算机网络协议栈中最高层的协议&#xff0c;它定义了运行在不同主机上…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂&#xff08;如抗体、抑制肽&#xff09;在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上&#xff0c;高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术&#xff0c;但这类方法普遍面临资源消耗巨大、研发周期冗长…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器

——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的​​一体化测试平台​​&#xff0c;覆盖应用全生命周期测试需求&#xff0c;主要提供五大核心能力&#xff1a; ​​测试类型​​​​检测目标​​​​关键指标​​功能体验基…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

智能仓储的未来:自动化、AI与数据分析如何重塑物流中心

当仓库学会“思考”&#xff0c;物流的终极形态正在诞生 想象这样的场景&#xff1a; 凌晨3点&#xff0c;某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径&#xff1b;AI视觉系统在0.1秒内扫描包裹信息&#xff1b;数字孪生平台正模拟次日峰值流量压力…...