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

Linux - 进程间通信(3)

目录

3、解决遗留BUG -- 边关闭信道边回收进程

1)解决方案

2)两种方法相比较

4、命名管道

1)理解命名管道

2)创建命名管道

a. 命令行指令

b. 系统调用方法

3)代码实现命名管道

构建类进行封装命名管道:

构造和析构:

读取管道、写入管道:

server.cc (读端):

client.cc(写端):

效果:

4)疑点解决

写端未来,读端open调用阻塞

读端关闭,写端继续写入

5)完整代码

namedPipe.hpp:

server.cc:

client.cc:


3、解决遗留BUG -- 边关闭信道边回收进程

1)解决方案

我们仍然想用上述方法进行管道和子进程的回收

-- 则需要解决子进程所继承的父进程遗留的多余wfd,我们在每次创建子进程时,遍历所有之前的信道,关闭掉wfd即可,就不会出现,多个wfd指向一个管道

2)两种方法相比较

退一个回收一个:

先全部退出,再进行等待回收:

4、命名管道

1)理解命名管道

命名:该管道有名字,因为该文件有路径,有路径必有文件名

管道:依旧是一个内存级的基于文件进行通信的通信方案

属性、操作、文件内核缓冲区同一个文件的都是差不多的,因此不用再创建一份,操作系统不做浪费时间和空间的事情

我们怎么保证两个毫不相关的进程打开了同一个文件呢??
每一个文件,都有文件路径(唯一性)

2)创建命名管道

a. 命令行指令

一个进程(echo)向命名管道里面输入数据

一个进程(cat)向命名管道里面读取数据

这样就实现了两个毫不相关的进行之间的通信

创建了三个窗口,一个一直向管道输入,一个一直读取,一个手动检测管道大小

但是我们可以看到管道文件(myfifo)的大小一直显示0

因为 FIFO0 文件虽存在于文件系统中,但其内容都存放在内存里,不会将通信数据刷新到磁盘中,所以在磁盘上显示的文件大小始终为0

b. 系统调用方法

使用mkfifo即可创建管道文件

使用unlink即可删除一个管道文件(当然,rm也可以删除)

3)代码实现命名管道

创建两个.cc文件分别模拟两个进程,一个进行发送,一个进行读取

通过一个CreateNamedPipe和一个RemoveNamedPipe就可以实现对管道生命周期的管理

当然,我们管理管道的声明周期时,肯定是将创建和删除交给同一个文件去做比较好,因为它清楚什么时候去删除合适

这里我们让发送的那方去管理管道的生命周期

构建类进行封装命名管道:

我们需要创建管道的路径(共同路径)、创建管道的身份、管道的文件描述符

class NamedPipe
{
private:const std::string _fifo_path;int _id;int _fd;
};
构造和析构:
class NamedPipe
{
public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
读取管道、写入管道:
class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(), mode);if(_fd < 0) return false;return true;}public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0; // '\0'*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc (读端):
#include "namedPipe.hpp"// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言,如果我们打开了文件,但是写还没有来,我们会阻塞在open调中,直到对方打开// --> 一种变向的进程同步if (fifo.OpenForRead()){std::cout << "Server open named pipe done" << std::endl; // 为了检测阻塞sleep(3);while (true){std::string message;int n = fifo.ReadNamedPipe(&message);if (n > 0) // 正常接收{std::cout << "Client Say > " << message << std::endl;}else if(n == 0) // 即写端关闭{std::cout << "Client quit, Server too!" << std::endl;break;}else {std::cout << "fifo.ReadNamedPipe Error!" << std::endl;break;}}}return 0;
}
client.cc(写端):
#include "namedPipe.hpp"// client -- write
int main()
{NamedPipe fifo(comm_path, User); // 以非创建身份实例化if(fifo.OpenForWrite()){std::cout << "client open named pipe done" << std::endl;while(true){std::cout << "Please Enter > ";std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}
效果:

实现了两个进程(无父子关系)之间的通信

4)疑点解决

写端未来,读端open调用阻塞

读端关闭,写端继续写入

5)完整代码

namedPipe.hpp:
#pragma once#include <iostream>
#include <string>
#include <cstdio>
#include <cerrno>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>const std::string comm_path = "./myfifo";#define DefaultFd -1
#define Creater 1
#define User 2
#define Read O_RDONLY
#define Write O_WRONLY
#define BaseSize 4096class NamedPipe
{
private:bool OpenNamedPipe(int mode){_fd = open(_fifo_path.c_str(), mode);if(_fd < 0) return false;return true;}public:NamedPipe(const std::string &path, int who): _fifo_path(path), _id(who), _fd(DefaultFd){if (_id == Creater){int res = mkfifo(_fifo_path.c_str(), 0666);if (res != 0){perror("mkfifo");}std::cout << "creater create named pipe" << std::endl;}}bool OpenForRead(){return OpenNamedPipe(Read);}bool OpenForWrite(){return OpenNamedPipe(Write);}int ReadNamedPipe(std::string *out){char buffer[BaseSize];int n = read(_fd, buffer, sizeof(buffer));if(n > 0){buffer[n] = 0; // '\0'*out = buffer;}return n;}int WriteNamedPipe(const std::string &in){return write(_fd, in.c_str(), in.size());}~NamedPipe(){sleep(5);if (_id == Creater){int res = unlink(_fifo_path.c_str());if (res != 0){perror("unlink");}std::cout << "creater remove named pipe" << std::endl;}if(_fd != DefaultFd) close(_fd);}private:const std::string _fifo_path;int _id;int _fd;
};
server.cc:
#include "namedPipe.hpp"// server -- read : 管理命名管道的整个生命周期
int main()
{NamedPipe fifo(comm_path, Creater);// 对于读端而言,如果我们打开了文件,但是写还没有来,我们会阻塞在open调中,直到对方打开// --> 一种变向的进程同步if (fifo.OpenForRead()){std::cout << "Server open named pipe done" << std::endl;sleep(3);while (true){std::string message;int n = fifo.ReadNamedPipe(&message);if (n > 0){std::cout << "Client Say > " << message << std::endl;}else if(n == 0){std::cout << "Client quit, Server too!" << std::endl;break;}else{std::cout << "fifo.ReadNamedPipe Error!" << std::endl;break;}}}return 0;
}
client.cc:
#include "namedPipe.hpp"// client -- write
int main()
{NamedPipe fifo(comm_path, User);if(fifo.OpenForWrite()){std::cout << "client open named pipe done" << std::endl;while(true){std::cout << "Please Enter > ";std::string message;std::getline(std::cin, message);fifo.WriteNamedPipe(message);}}return 0;
}

相关文章:

Linux - 进程间通信(3)

目录 3、解决遗留BUG -- 边关闭信道边回收进程 1&#xff09;解决方案 2&#xff09;两种方法相比较 4、命名管道 1&#xff09;理解命名管道 2&#xff09;创建命名管道 a. 命令行指令 b. 系统调用方法 3&#xff09;代码实现命名管道 构建类进行封装命名管道&#…...

3、C#基于.net framework的应用开发实战编程 - 实现(三、三) - 编程手把手系列文章...

三、 实现&#xff1b; 三&#xff0e;三、编写应用程序&#xff1b; 此文主要是实现应用的主要编码工作。 1、 分层&#xff1b; 此例子主要分为UI、Helper、DAL等层。UI负责便签的界面显示&#xff1b;Helper主要是链接UI和数据库操作的中间层&#xff1b;DAL为对数据库的操…...

C++编程语言:抽象机制:泛型编程(Bjarne Stroustrup)

泛型编程(Generic Programming) 目录 24.1 引言(Introduction) 24.2 算法和(通用性的)提升(Algorithms and Lifting) 24.3 概念(此指模板参数的插件)(Concepts) 24.3.1 发现插件集(Discovering a Concept) 24.3.2 概念与约束(Concepts and Constraints) 24.4 具体化…...

Python面试宝典13 | Python 变量作用域,从入门到精通

今天&#xff0c;我们来深入探讨一下 Python 中一个非常重要的概念——变量作用域。理解变量作用域对于编写清晰、可维护、无 bug 的代码至关重要。 什么是变量作用域&#xff1f; 简单来说&#xff0c;变量作用域就是指一个变量在程序中可以被访问的范围。Python 中有四种作…...

基于最近邻数据进行分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import numpy as np from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import matplotlib.pyplot as plt# 生成一个简单的数据…...

DeepSeek V3 vs R1:大模型技术路径的“瑞士军刀“与“手术刀“进化

DeepSeek V3 vs R1&#xff1a;——大模型技术路径的"瑞士军刀"与"手术刀"进化 大模型分水岭&#xff1a;从通用智能到垂直突破 2023年&#xff0c;GPT-4 Turbo的发布标志着通用大模型进入性能瓶颈期。当模型参数量突破万亿级门槛后&#xff0c;研究者们开…...

一、TensorFlow的建模流程

1. 数据准备与预处理&#xff1a; 加载数据&#xff1a;使用内置数据集或自定义数据。 预处理&#xff1a;归一化、调整维度、数据增强。 划分数据集&#xff1a;训练集、验证集、测试集。 转换为Dataset对象&#xff1a;利用tf.data优化数据流水线。 import tensorflow a…...

指导初学者使用Anaconda运行GitHub上One - DM项目的步骤

以下是指导初学者使用Anaconda运行GitHub上One - DM项目的步骤&#xff1a; 1. 安装Anaconda 下载Anaconda&#xff1a; 让初学者访问Anaconda官网&#xff08;https://www.anaconda.com/products/distribution&#xff09;&#xff0c;根据其操作系统&#xff08;Windows、M…...

7层还是4层?网络模型又为什么要分层?

~犬&#x1f4f0;余~ “我欲贱而贵&#xff0c;愚而智&#xff0c;贫而富&#xff0c;可乎&#xff1f; 曰&#xff1a;其唯学乎” 一、为什么要分层 \quad 网络通信的复杂性促使我们需要一种分层的方法来理解和管理网络。就像建筑一样&#xff0c;我们不会把所有功能都混在一起…...

C++:抽象类习题

题目内容&#xff1a; 求正方体、球、圆柱的表面积&#xff0c;抽象出一个公共的基类Container为抽象类&#xff0c;在其中定义一个公共的数据成员radius(此数据可以作为正方形的边长、球的半径、圆柱体底面圆半径)&#xff0c;以及求表面积的纯虚函数area()。由此抽象类派生出…...

C++ 泛型编程指南02 (模板参数的类型推导)

文章目录 一 深入了解C中的函数模板类型推断什么是类型推断&#xff1f;使用Boost TypeIndex库进行类型推断分析示例代码关键点解析 2. 理解函数模板类型推断2.1 指针或引用类型2.1.1 忽略引用2.1.2 保持const属性2.1.3 处理指针类型 2.2 万能引用类型2.3 传值方式2.4 传值方式…...

音视频入门基础:RTP专题(5)——FFmpeg源码中,解析SDP的实现

一、引言 FFmpeg源码中通过ff_sdp_parse函数解析SDP。该函数定义在libavformat/rtsp.c中&#xff1a; int ff_sdp_parse(AVFormatContext *s, const char *content) {const char *p;int letter, i;char buf[SDP_MAX_SIZE], *q;SDPParseState sdp_parse_state { { 0 } }, *s1…...

计算机网络 应用层 笔记 (电子邮件系统,SMTP,POP3,MIME,IMAP,万维网,HTTP,html)

电子邮件系统&#xff1a; SMTP协议 基本概念 工作原理 连接建立&#xff1a; 命令交互 客户端发送命令&#xff1a; 服务器响应&#xff1a; 邮件传输&#xff1a; 连接关闭&#xff1a; 主要命令 邮件发送流程 SMTP的缺点: MIME&#xff1a; POP3协议 基本概念…...

【视频+图文详解】HTML基础3-html常用标签

图文教程 html常用标签 常用标签 1. 文档结构 <!DOCTYPE html>&#xff1a;声明HTML文档类型。<html>&#xff1a;定义HTML文档的根元素。<head>&#xff1a;定义文档头部&#xff0c;包含元数据。<title>&#xff1a;设置网页标题&#xff0c;浏览…...

FreeRTOS学习 --- 消息队列

队列简介 队列是任务到任务、任务到中断、中断到任务数据交流的一种机制&#xff08;消息传递&#xff09; 全局变量的弊端&#xff1a;数据无保护&#xff0c;导致数据不安全&#xff0c;当多个任务同时对该变量操作时&#xff0c;数据易受损 使用队列的情况如下&#xff1a;…...

PHP If...Else 语句详解

PHP If...Else 语句详解 引言 在PHP编程中&#xff0c;if...else语句是流程控制的重要组成部分&#xff0c;它允许程序根据条件判断执行不同的代码块。本文将详细解析PHP中的if...else语句&#xff0c;包括其基本用法、高级技巧以及注意事项。 一、基本用法 if...else语句的…...

pytorch使用SVM实现文本分类

人工智能例子汇总&#xff1a;AI常见的算法和例子-CSDN博客 完整代码&#xff1a; import torch import torch.nn as nn import torch.optim as optim import jieba import numpy as np from sklearn.model_selection import train_test_split from sklearn.feature_extract…...

安卓(android)读取手机通讯录【Android移动开发基础案例教程(第2版)黑马程序员】

一、实验目的&#xff08;如果代码有错漏&#xff0c;可在代码地址查看&#xff09; 1.熟悉内容提供者(Content Provider)的概念和作用。 2.掌握内容提供者的创建和使用方法。 4.掌握内容URI的结构和用途。 二、实验条件 1.熟悉内容提供者的工作原理。 2.掌握内容提供者访问其…...

【Qt】常用的容器

Qt提供了多个基于模板的容器类&#xff0c;这些容器类可用于存储指定类型的数据项。例如常用的字符串列表类 QStringList 可用来操作一个 QList<QString>列表。 Qt的容器类比标准模板库(standard template library&#xff0c;STL)中的容器类更轻巧、使用更安全且更易于使…...

基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于UKF-IMM无迹卡尔曼滤波与交互式多模型的轨迹跟踪算法matlab仿真,对比EKF-IMM和UKF。 2.测试软件版本以及运行结果展示 MATLAB2022A版本运行 3.核心程序 .…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法

深入浅出&#xff1a;JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中&#xff0c;随机数的生成看似简单&#xff0c;却隐藏着许多玄机。无论是生成密码、加密密钥&#xff0c;还是创建安全令牌&#xff0c;随机数的质量直接关系到系统的安全性。Jav…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

《C++ 模板》

目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板&#xff0c;就像一个模具&#xff0c;里面可以将不同类型的材料做成一个形状&#xff0c;其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式&#xff1a;templa…...

20个超级好用的 CSS 动画库

分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码&#xff0c;而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库&#xff0c;可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画&#xff0c;可以包含在你的网页或应用项目中。 3.An…...

libfmt: 现代C++的格式化工具库介绍与酷炫功能

libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库&#xff0c;提供了高效、安全的文本格式化功能&#xff0c;是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全&#xff1a…...