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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/11694.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言 --- 分支

C语言 --- 分支 语句分支语句含义if...else语句单分支if语句语法形式 双分支 if-else 语句语法形式 悬空else含义问题描述 多分支 if-else 语句语法形式 switch...case语句含义语法形式 总结 &#x1f4bb;作者简介&#xff1a;曾与你一样迷茫&#xff0c;现以经验助你入门 C 语…

SSRF 漏洞利用 Redis 实战全解析:原理、攻击与防范

目录 前言 SSRF 漏洞深度剖析 Redis&#xff1a;强大的内存数据库 Redis 产生漏洞的原因 SSRF 漏洞利用 Redis 实战步骤 准备环境 下载安装 Redis 配置漏洞环境 启动 Redis 攻击机远程连接 Redis 利用 Redis 写 Webshell 防范措施 前言 在网络安全领域&#xff0…

Spring Boot - 数据库集成06 - 集成ElasticSearch

Spring boot 集成 ElasticSearch 文章目录 Spring boot 集成 ElasticSearch一&#xff1a;前置工作1&#xff1a;项目搭建和依赖导入2&#xff1a;客户端连接相关构建3&#xff1a;实体类相关注解配置说明 二&#xff1a;客户端client相关操作说明1&#xff1a;检索流程1.1&…

深度学习之“线性代数”

线性代数在深度学习中是解决多维数学对象计算问题的核心工具。这些数学对象包括标量、向量、矩阵和张量&#xff0c;借助它们可以高效地对数据进行操作和建模。以下将详细介绍这些数学对象及其在深度学习中的典型用途。 数学对象概述 标量 标量是最简单的数学对象&#xff0…

使用PyQt5绘制带有刻度的温度计控件

前言&#xff1a;进入学习Python开发上位机界面的第二阶段&#xff0c;学习如何开发自定义控件&#xff0c;从常用的控件入手学习&#xff0c;本期主要学习如何使用PyQt5绘制带有刻度的温度计控件。 1. 先找到一篇参考文章 参考文章&#xff1a;Qt编写自定义控件5-柱状温度计…

问deepseek,如何看待ai降低学习成本而导致软件开发岗位需求降低,和工资下降。 软件从业人员何去何从?

它给我的回答是这样的&#xff1a; 思考逻辑 嗯&#xff0c;用户问的是AI如何降低学习成本&#xff0c;进而导致软件开发岗位需求减少和工资下降&#xff0c;以及软件从业人员该怎么办。这个问题挺复杂的&#xff0c;我得先理清楚各个部分。首先&#xff0c;AI确实在改变很多行…

Error: Expected a mutable image

你的函数用了不支持的图片格式比如我的人脸检测&#xff0c;本来要RGB565我却用JPEG所以报错

海思ISP开发说明

1、概述 ISP&#xff08;Image Signal Processor&#xff09;图像信号处理器是专门用于处理图像信号的硬件或处理单元&#xff0c;广泛应用于图像传感器&#xff08;如 CMOS 或 CCD 传感器&#xff09;与显示设备之间的信号转换过程中。ISP通过一系列数字图像处理算法完成对数字…

2.攻防世界PHP2及知识点

进入题目页面如下 意思是你能访问这个网站吗&#xff1f; ctrlu、F12查看源码&#xff0c;什么都没有发现 用kali中的dirsearch扫描根目录 命令如下&#xff0c;根据题目提示以及需要查看源码&#xff0c;扫描以php、phps、html为后缀的文件 dirsearch -u http://61.147.17…

线性数据结构:单向链表

放弃眼高手低&#xff0c;你真正投入学习&#xff0c;会因为找到一个新方法产生成就感&#xff0c;学习不仅是片面的记单词、学高数......只要是提升自己的过程&#xff0c;探索到了未知&#xff0c;就是学习。 目录 一.链表的理解 二.链表的分类&#xff08;重点理解&#xf…

【AI】探索自然语言处理(NLP):从基础到前沿技术及代码实践

Hi &#xff01; 云边有个稻草人-CSDN博客 必须有为成功付出代价的决心&#xff0c;然后想办法付出这个代价。 目录 引言 1. 什么是自然语言处理&#xff08;NLP&#xff09;&#xff1f; 2. NLP的基础技术 2.1 词袋模型&#xff08;Bag-of-Words&#xff0c;BoW&#xff…

书生大模型实战营7

文章目录 L1——基础岛提示词工程实践什么是Prompt(提示词)什么是提示工程提示设计框架CRISPECO-STAR LangGPT结构化提示词LangGPT结构编写技巧构建全局思维链保持上下文语义一致性有机结合其他 Prompt 技巧 常用的提示词模块 浦语提示词工程实践(LangGPT版)自动化生成LangGPT提…

一个开源 GenBI AI 本地代理(确保本地数据安全),使数据驱动型团队能够与其数据进行互动,生成文本到 SQL、图表、电子表格、报告和 BI

一、GenBI AI 代理介绍&#xff08;文末提供下载&#xff09; github地址&#xff1a;https://github.com/Canner/WrenAI 本文信息图片均来源于github作者主页 在 Wren AI&#xff0c;我们的使命是通过生成式商业智能 &#xff08;GenBI&#xff09; 使组织能够无缝访问数据&…

41. 缺失的第一个正数

参考题解&#xff1a;https://leetcode.cn/problems/first-missing-positive/solutions/7703/tong-pai-xu-python-dai-ma-by-liweiwei1419 难点在于时间复杂度控制在O(n)&#xff0c;空间复杂度为常数级。 哈希表时间复杂度符合&#xff0c;但是空间复杂度为O(n) 排序空间复杂…

深入核心:一步步手撕Tomcat搭建自己的Web服务器

介绍&#xff1a; servlet&#xff1a;处理 http 请求 tomcat&#xff1a;服务器 Servlet servlet 接口&#xff1a; 定义 Servlet 声明周期初始化&#xff1a;init服务&#xff1a;service销毁&#xff1a;destory 继承链&#xff1a; Tomcat Tomcat 和 servlet 原理&#x…

final-关键字

一、final修饰的类不能被继承 当final修饰一个类时&#xff0c;表明这个类不能被其他类继承。例如&#xff0c;在 Java 中&#xff0c;String类就是被final修饰的&#xff0c;这保证了String类的不可变性和安全性&#xff0c;防止其他类通过继承来改变String类的行为。 final…

51单片机 01 LED

一、点亮一个LED 在STC-ISP中单片机型号选择 STC89C52RC/LE52RC&#xff1b;如果没有找到hex文件&#xff08;在objects文件夹下&#xff09;&#xff0c;在keil中options for target-output- 勾选 create hex file。 如果要修改编程 &#xff1a;重新编译-下载/编程-单片机重…

知识库建设与知识管理实践对企业发展的助推作用探索

内容概要 在当今瞬息万变的商业环境中&#xff0c;知识库建设与知识管理实践日益成为企业发展的重要驱动力。知识库作为组织内信息和知识的集成&#xff0c;起着信息存储、整理和共享的关键作用。通过有效的知识库建设&#xff0c;企业不仅能够提升员工获取信息的便利性&#…

【Pytorch和Keras】使用transformer库进行图像分类

目录 一、环境准备二、基于Pytorch的预训练模型1、准备数据集2、加载预训练模型3、 使用pytorch进行模型构建 三、基于keras的预训练模型四、模型测试五、参考 现在大多数的模型都会上传到huggface平台进行统一的管理&#xff0c;transformer库能关联到huggface中对应的模型&am…

如何使用 DeepSeek 和 Dexscreener 构建免费的 AI 加密交易机器人?

我使用DeepSeek AI和Dexscreener API构建的一个简单的 AI 加密交易机器人实现了这一目标。在本文中&#xff0c;我将逐步指导您如何构建像我一样的机器人。 DeepSeek 最近发布了R1&#xff0c;这是一种先进的 AI 模型。您可以将其视为 ChatGPT 的免费开源版本&#xff0c;但增加…