17.进程间通信(三)

article/2025/7/14 19:36:19

一、System V 消息队列基本结构与理解

消息队列是全双工通信,可以同时收发消息。

结论1:消息队列提供了一种,一个进程给另一个进程发送有类型数据块的方式!

结论2:OS中消息队列可能有多个,要对消息队列进行管理,先描述,在组织。

结论3:两个进程怎么保证看到的是同一个消息队列?用户层约定的key值。

结论4:每个消息队列的总的字节数也是有上限的(MSGMNB),系统上消息队列的总数也有上限 (MSGMNI)的。
结论5:消息队列的生命周期也是随内核的。

数据块结构:

struct msgbuf {long mtype;       /* message type, must be > 0 */char mtext[1];    /* message data */
};

其中mtype为数据类型,由用户层约定,规定必须是大于0的数字。

mtext为数据内容,大小由用户层自定义。

消息队列的数据结构:

二、消息队列的相关接口

1.创建消息队列

int msgget(key_t key, int msgflg);

key为用户层约定标识消息队列唯一性的值。

msgflg,选项IPC_CREAT:不存在就新建,存在就返回现存的。IPC_EXCL:与IPC_CREAT配合使用,不存在就新建,存在就出错返回。

返回值:成功返回消息队列描述符,失败返回-1,错误码被设置。

2.删除消息队列

int msgctl(int msqid, int cmd, struct msqid_ds *buf);

msqid为消息队列描述符。

cmd为对应的操作:

简单点说:IPC_STAT往外带值,IPC_SET往内设值。

buf既可以作输出型参数又可以作输入性参数。

strcut msqid_ds的结构如下:

3.收发消息

发消息:

int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg);

msqid为消息队列标识符。

msqp为消息体,即:

struct msgbuf {long mtype;       /* message type, must be > 0 */char mtext[1];    /* message data */
};

msgsz为消息内容大小,注意不包括类型,只是数据的大小。

msgflg:控制着当前消息队列满 或 到达系统上限 时将要发生的事情, 0即。msgflg=IPC_NOWAIT 表示队列满不等待,返回 EAGAIN 错误 。

返回值:成功0返回,失败-1返回,错误码被设置。

收消息:

ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg);

大体同上,mgstyp为数据类型,msgp在此为输出型参数,带出数据内容。

返回值:成功为消息的数据内容大小,失败返回-1,错误码被设置。

4.msgqueue接口使用

msgqueue.hpp

#ifndef MSGQUEUE_HPP
#define MSGQUEUE_HPP#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>#define PATH_NAME "."
#define PROJ_ID 1
#define MODE_DEFAULT 0666
#define DATA_SIZE 1024
#define EXIT_ERROR(m) \do                \{                 \perror(m);    \exit(1);      \} while (0)class Msgqueue
{struct Msgbuf{long mtype;char mtext[DATA_SIZE];};protected:Msgqueue(){_key = ftok(PATH_NAME, PROJ_ID);std::cout << "Msgqueue() key:0x" << std::hex << _key << std::endl;}~Msgqueue(){}void Getmsqid(const int msgflg){_msqid = msgget(_key, msgflg);if (_msqid < 0){EXIT_ERROR("msgget");}std::cout << "msgget success! msqid:" << _msqid << std::endl;}void Destroy(){int ret = msgctl(_msqid, IPC_RMID, nullptr);if (ret < 0){EXIT_ERROR("msgctl");}std::cout << "msgrm success! msqid:" << _msqid << std::endl;}void Send(const std::string &msg, const long type){Msgbuf buf;buf.mtype = type;strcpy(buf.mtext, msg.c_str());int ret = msgsnd(_msqid, &buf, DATA_SIZE, 0);if (ret < 0){EXIT_ERROR("msgsnd");}}void Receive(std::string &msg, const long type){Msgbuf buf;ssize_t n = msgrcv(_msqid, &buf, DATA_SIZE, type, 0);if (n < 0){EXIT_ERROR("msgrcv");}buf.mtext[n] = 0;msg = buf.mtext;}void Stat(){struct msqid_ds ms;int ret = msgctl(_msqid, IPC_STAT, &ms);std::cout << "Stat key:0x" << std::hex << ms.msg_perm.__key << std::endl;}protected:int _msqid;key_t _key;
};const long server_type = 1;
const long client_type = 2;class Server : public Msgqueue
{
public:Server(){Msgqueue::Getmsqid(IPC_CREAT | IPC_EXCL | MODE_DEFAULT);Stat();}~Server(){Msgqueue::Destroy();}void Receive(std::string &msg){Msgqueue::Receive(msg, client_type);}
};class Client : public Msgqueue
{
public:Client(){Getmsqid(IPC_CREAT);Stat();}~Client(){}void Send(const std::string &msg){Msgqueue::Send(msg, client_type);}
};#endif

三、责任链模式(Chain of Responsibility Pattern)

新需求:
1.client 发送给 server 的输入内容,拼接上时间,进程pid信息。
2.server 收到的内容持久化保存到文件中。
3.文件的内容如果过大,要进行切片保存并在指定的目录下打包保存,命令自定义。
实现结构:
责任链模式,基类HandlerText,派生类HandlerTextFormat,HandlerTextSaveFile,HandlerTextBackupFile分别处理文本格式化,写入到文件,备份并打包。采用链式结构,将这些加工过程链接起来,加工之后给下一个任务进行处理。并设置任务的开关,以此实现功能的裁剪。
实现细节:
采用C++17 filesystem和fstream来处理文件操作。
注意点:
tar命令打包文件如果带上路径会递归式生成目录并打包,因此要切换到指定目录在打包。
验证程序退出的状态码,WIFEXITED(status) 验证子进程是否正常返回,值大于0则表示正常退出,WEXITSTATUS(status) 值为子进程的退出码,两者结合使用。
实现代码如下:
#ifndef CHAIN_OF_RESP_HPP
#define CHAIN_OF_RESP_HPP#include <iostream>
#include <string>
#include <memory>
#include <filesystem>
#include <fstream>
#include <ctime>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>#define PATH_DEFAULT "./tmp/"
#define FILE_DEFAULT "text.log"
#define EXIT_ERROR(m) \do                \{                 \perror(m);    \exit(1);      \} while (0)class HandlerText
{public:virtual void Excute(const std::string &msg) = 0;void SetNext(const std::shared_ptr<HandlerText> &next){_next = next;}void Disable() { _status = false; }void Enable() { _status = true; }bool Stat() { return _status; }protected:std::shared_ptr<HandlerText> _next;private:bool _status = true;
};// 格式化内容,拼接上时间戳和进程pid
class HandlerTextFormat : public HandlerText
{
public:HandlerTextFormat(const std::string &pathname, const std::string &filename): _pathname(pathname), _filename(filename){}~HandlerTextFormat(){}virtual void Excute(const std::string &msg){std::string format = msg + "\n";// 动态裁剪if (Stat()){std::cout << "step 1:文本格式化" << std::endl;std::string cur = std::to_string((int)time(nullptr));format += "时间戳:" + cur + " 进程pid:" + std::to_string(getpid()) + "\n";}else{std::cout << "step 1:文本格式化(已禁用)" << std::endl;}if (_next){_next->Excute(format);}else{std::cout << "责任链终止在HandlerTextFormat" << std::endl;}}private:std::string _pathname;std::string _filename;
};// 把msg写到文件中
class HandlerTextSaveFile : public HandlerText
{
public:HandlerTextSaveFile(const std::string &pathname, const std::string &filename): _pathname(pathname), _filename(filename){if (std::filesystem::exists(_pathname))return;// 递归创建目录结构try{std::filesystem::create_directories(_pathname);}catch (const std::filesystem::filesystem_error &e){std::cerr << e.what() << std::endl;exit(1);}}virtual void Excute(const std::string &msg){if (Stat()){std::cout << "step 2:文本保存到文件" << std::endl;std::string file = _pathname + _filename;std::ofstream append_file(file, std::ios::app);if (!append_file.is_open()){EXIT_ERROR("open file");}// 写入文件,追加写入append_file << msg;append_file.close();}else{std::cout << "step 2:文本保存到文件(已禁用)" << std::endl;}if (_next){_next->Excute(msg);}else{std::cout << "责任链终止在HandlerTextSaveFile" << std::endl;}}private:std::string _pathname;std::string _filename;
};const int maxLineSize = 5;// 备份(改名,改名成文件名拼接上时间戳),打包文件,删除源文件
class HandlerTextBackupFile : public HandlerText
{
private:bool LineOverFlow(){std::string file = _pathname + _filename;std::ifstream read_file(file);if (!read_file.is_open()){EXIT_ERROR("open file");}std::string line;int lineCount = 0;while (std::getline(read_file, line)){lineCount++;}read_file.close();if (lineCount > _maxLineSize){return true;}return false;}// 备份void Backup(){std::string file = _pathname + _filename;// 新文件名std::string backup_filename = _filename + "." + std::to_string((int)time(nullptr));_backup_filename = backup_filename;std::string backup_file = _pathname + backup_filename;// 重命名std::filesystem::rename(file, backup_file);}// 打包并删除源文件void PackAndDelete(){std::string pack_filename = _backup_filename + ".tgz";pid_t pid = fork();if (pid == 0){// 改变子进程工作路径至_pathname用C++方式std::filesystem::current_path(_pathname);// 子进程程序替换执行tar命令,打包文件execlp("tar", "tar", "-czf", pack_filename.c_str(), _backup_filename.c_str(), nullptr);exit(1);}int status;int ret = waitpid(pid, &status, 0);if (ret < 0){EXIT_ERROR("waitpid");}else{// 子进程正常退出,且退出码为0,删除源文件if (WIFEXITED(status) && WEXITSTATUS(status) == 0){std::filesystem::path file = _pathname + _backup_filename;std::filesystem::remove(file);}}}public:HandlerTextBackupFile(const std::string &pathname, const std::string &filename): _pathname(pathname), _filename(filename), _maxLineSize(maxLineSize){}virtual void Excute(const std::string &msg){if (Stat()){std::cout << "step 3:文本备份" << std::endl;// 备份if (LineOverFlow()){std::cout << "超过最大行数限制,备份" << std::endl;Backup();std::cout << "备份文件名:" << _backup_filename << std::endl;std::cout << "打包并删除备份文件" << std::endl;PackAndDelete();}}else{std::cout << "step 3:文本备份(已禁用)" << std::endl;}if (_next){_next->Excute(msg);}else{std::cout << "责任链终止在HandlerTextBackupFile" << std::endl;}}private:std::string _pathname;std::string _filename;std::string _backup_filename;int _maxLineSize;
};class HandlerEntry
{
private:void StatSet(bool e1, bool e2, bool e3){e1 ? _format->Enable() : _format->Disable();e2 ? _save->Enable() : _save->Disable();e3 ? _backup->Enable() : _backup->Disable();}public:HandlerEntry(bool e1, bool e2, bool e3){_format = std::make_shared<HandlerTextFormat>(PATH_DEFAULT, FILE_DEFAULT);_save = std::make_shared<HandlerTextSaveFile>(PATH_DEFAULT, FILE_DEFAULT);_backup = std::make_shared<HandlerTextBackupFile>(PATH_DEFAULT, FILE_DEFAULT);_format->SetNext(_save);_save->SetNext(_backup);StatSet(e1, e2, e3);}void Run(const std::string &msg){_format->Excute(msg);}private:std::shared_ptr<HandlerTextFormat> _format;std::shared_ptr<HandlerTextSaveFile> _save;std::shared_ptr<HandlerTextBackupFile> _backup;
};#endif // CHAIN_OF_RESP_HPP

http://www.hkcw.cn/article/lidyvLUlMO.shtml

相关文章

【汽车电子入门】一文了解LIN总线

前言&#xff1a;LIN&#xff08;Local Interconnect Network&#xff09;总线&#xff0c;也就是局域互联网的意思&#xff0c;它的出现晚于CAN总线&#xff0c;于20世纪90年代末被摩托罗拉、宝马、奥迪、戴姆勒、大众以及沃尔沃等多家公司联合开发&#xff0c;其目的是提供一…

BayesFlow:基于神经网络的摊销贝叶斯推断框架

贝叶斯推断为不确定性条件下的推理、复杂系统建模以及基于观测数据的预测提供了严谨且功能强大的理论框架。尽管贝叶斯建模在理论上具有优雅性&#xff0c;但在实际应用中经常面临显著的计算挑战&#xff1a;后验分布通常缺乏解析解&#xff0c;模型验证和比较需要进行重复的推…

高压电绝缘子破损目标检测数据集简介与应用

在电力系统中&#xff0c;高压电绝缘子起着关键的绝缘与机械支撑作用。一旦发生破损&#xff0c;不仅影响输电线路的安全运行&#xff0c;还可能引发电力事故。因此&#xff0c;利用目标检测技术对高压绝缘子的破损情况进行智能识别&#xff0c;已成为当前电力巡检中的重要研究…

深度学习与神经网络 前馈神经网络

1.神经网络特征 无需人去告知神经网络具体的特征是什么&#xff0c;神经网络可以自主学习 2.激活函数性质 &#xff08;1&#xff09;连续并可导&#xff08;允许少数点不可导&#xff09;的非线性函数 &#xff08;2&#xff09;单调递增 &#xff08;3&#xff09;函数本…

paoxiaomo的XCPC算法竞赛训练经验

楼主作为一个普通二本的ICPC选手&#xff0c;在0基础的情况下凭借自学&#xff0c;获得过南昌邀请赛金牌&#xff0c;杭州区域赛银牌&#xff0c;一路上经历过不少的跌宕起伏&#xff0c;如今将曾经摸索出来的学习路线分享给大家 一&#xff0c;语言基础 学习C语言基础语法&a…

电力系统时间同步系统

电力系统中&#xff0c;电压、电流、功率变化等特征量测量都是时间相关函数[1]&#xff0c;统一精准的时间源对于电网安全稳定运行至关重要&#xff0c;因此&#xff0c;电力系统运行规程[2]中明确要求继电保护装置、自动化装置、安全稳定控制系统、能量管理系统和生产信息管理…

Codeforces Round 1028 (Div. 2)(A-D)

题面链接&#xff1a;Dashboard - Codeforces Round 1028 (Div. 2) - Codeforces A. Gellyfish and Tricolor Pansy 思路 要知道骑士如果没了那么这个人就失去了攻击手段&#xff0c;贪心的来说我们只需要攻击血量少的即可&#xff0c;那么取min比较一下即可 代码 void so…

金属材料资料

一、金属材料 1. 黑色金属材料&#xff08;钢铁材料&#xff09; 铸铁&#xff08;含碳量&#xff1e;2.11%&#xff09; 分类&#xff1a; 按碳存在形式&#xff1a;白口铸铁&#xff08;硬脆&#xff0c;炼钢原料&#xff09;、灰口铸铁&#xff08;应用最广&#xff09;、…

mysql专题上

连接服务器 mysql -h 127.0.0.1 -P 3306 -u root -p -h后接的是要连接的部署了mysql的主机&#xff0c;127.0.0.1指的是单机访问&#xff0c;如果没有指令则直接连接本地 -P后接的是端口号 一般是3306 -u后接的是要登入的用户 -p指要登陆密码 如果要退出可以直接quit mysql…

DAY43打卡

浙大疏锦行 kaggle找到一个图像数据集&#xff0c;用cnn网络进行训练并且用grad-cam做可视化 进阶&#xff1a;并拆分成多个文件 fruit_cnn_project/ ├─ data/ # 存放数据集&#xff08;需手动创建&#xff0c;后续放入图片&#xff09; │ ├─ train/ …

蓝天影院订票网站的设计V3

1 绪 论 1.1 本课题研究背景 20世纪90年代中期以来&#xff0c;随着以Internet为代表的计算机技术&#xff0c;网络技术和信息技术的迅速发展&#xff0c;影院订票也逐渐转移到网络上[1][2]。伴随着我国计算机信息产业的飞速进步&#xff0c;计算机的开发应用已经遍布生活…

Python----目标检测(《YOLO9000: Better, Faster, Stronger》和YOLO-V2的原理与网络结构)

一、YOLO9000: Better, Faster, Stronger 1.1、基本信息 标题: YOLO9000: Better, Faster, Stronger 作者: Joseph Redmon, Ali Farhadi 机构: 华盛顿大学1, 艾伦人工智能研究所2 发布时间: 2016年&#xff08;根据arXiv编号1612.08242推断&#xff09; 论文链接: [1612.0…

力扣HOT100之动态规划:32. 最长有效括号

这道题放在动态规划里属实是有点难为人了&#xff0c;感觉用动态规划来做反而更难理解了&#xff0c;这道题用索引栈来做相当好理解&#xff0c;这里先讲下索引栈的思路。 索引栈做法 我们定义一个存放整数的栈&#xff0c;定义一个全局变量result来记录最长有效子串的长度&a…

操作系统:文件系统笔记

文件系统 参考资料&#xff1a; 12.10 虚拟文件系统_哔哩哔哩_bilibili7.1 文件系统全家桶 | 小林coding 基本组成 文件系统是操作系统中负责管理持久数据的子系统&#xff0c;说简单点&#xff0c;就是负责把用户的文件存到磁盘硬件中&#xff0c;因为即使计算机断电了&#…

Docker 安装 Redis 容器

系列文章目录 文章目录 系列文章目录前言1 获取redis镜像2 创建和部署redis容器3 查看redis是否启动成功4 使用Redis客户端验证连接总结 前言 搭建环境&#xff1a; ubuntu22.04.05 docker redis: 7.0.10 测试环境&#xff1a; windows: win11 Redis测试客户端&#xff1a;Ti…

Spring Boot 3.X 下Redis缓存的尝试(二):自动注解实现自动化缓存操作

前言 上文我们做了在Spring Boot下对Redis的基本操作&#xff0c;如果频繁对Redis进行操作而写对应的方法显示使用注释更会更高效&#xff1b; 比如&#xff1a; 依之前操作对一个业务进行定入缓存需要把数据拉取到后再定入&#xff1b; 而今天我们可以通过注释的方式不需要额外…

【Linux】Ubuntu 20.04 英文系统显示中文字体异常

英文系统显示中文字体异常 新安装的 Ubuntu 20.04 英文系统&#xff0c;显示中文字体有些奇怪&#xff0c;比如在谷歌浏览器中中文字体显示效果如下 参考 英文版ubuntu默认中文显示很奇怪 解决方案 - dbxxx - 博客园 编辑文件 sudo gedit /etc/fonts/conf.avail/64-languag…

每天总结一个html标签——a标签

文章目录 一、定义与使用说明二、支持的属性三、支持的事件四、默认样式五、常见用法1. 文本链接2. 图片链接3. 导航栏 在前端开发中&#xff0c;a标签&#xff08;锚点标签&#xff09;是最常用的HTML标签之一&#xff0c;主要用于创建超链接&#xff0c;实现页面间的跳转或下…

Day10

1. ArrayList和LinkedList的区别&#xff1f; 底层结构&#xff1a;ArrayList 是基于动态数组实现&#xff0c;支持索引快速访问&#xff1b;LinkedList 是基于双向链表实现&#xff0c;依赖指针访问前后元素。插入与删除效率&#xff1a;在尾部操作时&#xff0c;两者性能相近…