【Linux C/C++开发】Linux系统轻量级的队列缓存mqueue
前言
开发设计时,通常会对业务流程进行模块化,有些流程之间,不要求同步,但又需要传递信息时,如果存储到数据库,效率降低很多,如果是存放在内存是最好的。此时可以选择系统的IPC(进程间通信,如共享内存等),本文讲解的是适合轻量级的队列缓存场景的mqueue。
功能讲解
mqueue特性
Linux的mqueue(消息队列)是POSIX标准中定义的进程间通信(IPC)机制,允许不同进程通过内核维护的队列传递结构化消息。其具备以下几个特性:
- 存储在指定文件:
mqueue消息队列文件默认挂载在/dev/mqueue目录下。通过mq_open创建的消息队列会在此目录生成对应文件节点,内核使用红黑树管理消息的存储与优先级 - 持久性:POSIX消息队列随系统重启消失
- 可在命令行查看队列信息:cat /dev/mqueue/[队列名] # 查看队列属性(如最大消息数、消息大小)
功能介绍
需求场景:某些功能需要在root用户下作为服务执行,组装的生产数据需要推送给登录系统桌面的普通用户权限的应用。
下面以在root权限下运行的读取usb信息的服务,监测USB的插拔事件并把信息推送到mqueue,而普通用户的应用通过读取mqueue获取USB插拔信息为例。
获取事件信息写入mqueue
#ifndef USBACTION_H_
#define USBACTION_H_
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>#include <cstdio>
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libudev.h>
#include <mqueue.h>
using namespace std;
#define MAX_NUM 100struct Message {long mtype; // 消息类型char mtext[256]; // 消息内容
};const int MSG_TYPE = 1;
const char* QUEUE_NAME = "/usb_msg";//在/dev/mqueue目录下class Usbaction: public TUtilBase {
public:Usbaction();~Usbaction();int Run();private://int Init();//初始化void monitorDevices();int sendtomqueue(const char* mqstr);unsigned int uSleepTime; //刷新间隔};#endif /* USBACTION_H_ */
#include "usbaction.h"std::vector<std::string> split(const std::string& str, char delimiter) {std::vector<std::string> tokens;std::istringstream tokenStream(str);std::string token;while (std::getline(tokenStream, token, delimiter)) {tokens.push_back(token);}return tokens;
}Usbaction::Usbaction() {uSleepTime = 5;
}Usbaction::~Usbaction() {
}int Usbaction::sendtomqueue(const char* mqstr){mqd_t mq;struct mq_attr attr;attr.mq_flags = O_NONBLOCK; // 设置为非阻塞模式attr.mq_maxmsg = MAX_NUM; // 队列中最大消息数attr.mq_msgsize = sizeof(Message);// 消息的最大大小(字节)attr.mq_curmsgs = 0; // 队列中当前消息数mq = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);if (mq == (mqd_t)-1) {WRITELOG(LOG_ERROR,"mq_open Error");return 0;}Message msg;msg.mtype = MSG_TYPE;strcpy(msg.mtext,mqstr);//attr.mq_flags |= O_NONBLOCK;if (mq_setattr(mq, &attr, NULL) == -1) {return 0;}if (mq_send(mq, reinterpret_cast<char*>(&msg), sizeof(msg), 0) == -1) {if (errno == EAGAIN) {} else {perror("mq_send");}}else {std::cout << "Message sent: " << msg.mtext << std::endl;}// 关闭消息队列mq_close(mq);return 1;
}void Usbaction::monitorDevices() {// 创建 udev 对象struct udev *udev = udev_new();if (!udev) {return;}// 创建 udev 监视器struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev");if (!mon) {udev_unref(udev);return;}// 添加过滤器以匹配usb 子系统udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", nullptr);udev_monitor_enable_receiving(mon);std::cout << "Monitoring block and USB events. Press Ctrl+C to exit." << std::endl;while (true) {struct udev_device *dev = udev_monitor_receive_device(mon);if (dev) {bool bfind=false;std::string level="";const char* subsystem = udev_device_get_subsystem(dev);const char* action = udev_device_get_action(dev);const char* devnode = udev_device_get_devnode(dev);const char *pro = udev_device_get_property_value(dev, "ID_USB_INTERFACES");if (subsystem && action && devnode) {if (strcmp(action,"add")==0||strcmp(action,"remove")==0){bfind=true;std::vector<std::string> tokens = split(devnode, '/');// 确保有至少两个分割结果if (tokens.size() >= 2) {string device = tokens[tokens.size() - 1];string bus = tokens[tokens.size() - 2];level = bus + ":" + device;}}}if (bfind) {const char* idVendor = udev_device_get_sysattr_value(dev,"idVendor");const char* idProduct = udev_device_get_sysattr_value(dev, "idProduct");if (idVendor && idProduct) {//strcmp(action,"add")==0char sendbuf[256]={0};if(pro){sprintf(sendbuf,"%s,%s,%s:%s,%s",action,level.c_str(),idVendor,idProduct,pro);}elsesprintf(sendbuf,"%s,%s,%s:%s",action,level.c_str(),idVendor,idProduct);sendtomqueue(sendbuf);
%s",action,level.c_str(),idVendor,idProduct);}else{char sendbuf[256]={0};sprintf(sendbuf,"%s,%s",action,level.c_str());sendtomqueue(sendbuf);}}udev_device_unref(dev);}usleep(500000); // Sleep for 0.5 seconds}udev_monitor_unref(mon);udev_unref(udev);
}int Usbaction::Init() {//logif (0== BInit(APP_TYPE_LOG, ACTIVITYCENSUS_LOG, 0)) {return 0;}return 1;
}int Usbaction::Run() {//初始化if (NS_FAILED == Init()) {return 0;}monitorDevices();return 1;
}int main(int argc, char **argv) {Usbaction action;action.Run();return 0;}
makefile
CC = g++
CFLAGS =
DEBUGFLAG = -g -Wall
MACRO =
#MACRO = -D_DEBUG
LIBDIRS =
LIBS = -ldl -ludev -lrt
INCLUDE =
MAKE_SO =
OPTIONS =
OBJDIR =
SRCDIR =
RUNOUTPUT = usbaction
LIBOUTPUT =
OBJS = usbaction.odefault:$(RUNOUTPUT)clean:rm -f $(OBJS) $(RUNOUTPUT)install:cp -f $(RUNOUTPUT) ../../bin$(RUNOUTPUT):$(OBJS)$(CC) -o $(RUNOUTPUT) $^ $(OPTIONS) $(LIBDIRS) $(LIBS).cpp.o:$(CC) $(DEBUGFLAG) $(MACRO) -fPIC -c $< -o $@ $(CFLAGS) $(INCLUDE)
读取mqueue
普通应用权限的应用可以读取root用户权限的mqueue文件,下面是非阻塞式读取队列数据。
#include <iostream>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <cstring>
#include <unistd.h>struct Message {long mtype; // 消息类型char mtext[256]; // 消息内容
};const char* QUEUE_NAME = "/ymore_msg"; // 消息队列的名称int main() {// 打开消息队列以读取模式mqd_t mq = mq_open(QUEUE_NAME, O_RDONLY | O_NONBLOCK);if (mq == (mqd_t)-1) {std::cerr << "Error opening message queue: " << strerror(errno) << std::endl;return 1;}Message msg;ssize_t bytes_read;// 循环接收消息while (true) {bytes_read = mq_receive(mq, reinterpret_cast<char*>(&msg), sizeof(msg), NULL);if (bytes_read == -1) {std::cerr << "Error receiving message: " << strerror(errno) << std::endl;break;}std::cout << "Received message: " << msg.mtext << std::endl;// 如果读取到队列为空,可以根据条件退出// 例如,使用 `mq_getattr()` 获取队列的当前状态struct mq_attr attr;if (mq_getattr(mq, &attr) == -1) {std::cerr << "Error getting queue attributes: " << strerror(errno) << std::endl;break;}// 如果队列中没有消息,退出循环if (attr.mq_curmsgs == 0) {std::cout << "No more messages in the queue." << std::endl;break;}}// 关闭消息队列mq_close(mq);return 0;
}
结尾
Linux后台C/C++项目,一般在架构设计时,可以设计共享内容来内部处理缓存数据,但也有考虑到第三方应用或者扩展型应用的场景,此时mqueue是比较合适了,如果是高并发的队列缓存,还是得找成熟的队列缓存中间件,比如kafka。
相关文章:
【Linux C/C++开发】Linux系统轻量级的队列缓存mqueue
前言 开发设计时,通常会对业务流程进行模块化,有些流程之间,不要求同步,但又需要传递信息时,如果存储到数据库,效率降低很多,如果是存放在内存是最好的。此时可以选择系统的IPC(进程…...
排查生产sql查询缓慢
生产投产检验,发现查询客户明细的接口数据响应需要5秒以上,通过接口可以查询到详细的后端代码 1. 先排查后端的代码实现,并未出现复杂逻辑,那么就应该是sql的问题 2. 通过explain对sql进行解析,发现sql没有走索引 3.…...
idea从远程gitee拉取项目
文章目录 从gitee上面拿到项目地址填写远程地址,并且设置项目保存位置拉取成功 从gitee上面拿到项目地址 填写远程地址,并且设置项目保存位置 拉取成功...
【UCB CS 61B SP24】Lecture 5 - Lists 3: DLLists and Arrays学习笔记
本文内容为构建双向循环链表、使用 Java 的泛型将其优化为通用类型的链表以及数组的基本语法介绍。 1. 双向链表 回顾上一节课写的代码,当执行 addLast() 与 getLast() 方法时需要遍历链表,效率不高,因此可以添加一个指向链表末尾的索引&am…...
软件测试与软件开发之间的关系
软件测试与软件开发的关系 软件测试(Software Testing)与软件开发(Software Development)是软件工程中的两个核心环节,它们相辅相成,确保软件的质量和功能满足需求。以下是两者之间的关系解析:…...
QT 建立一片区域某种颜色
绘制一个位于(50, 50)的200x200的红色矩形 #include "widget.h" #include "ui_widget.h" #include <QPainter>Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);update(); }Widget::~Widget() {delete…...
LeetCode--23. 合并 K 个升序链表【堆和分治】
23. 合并 K 个升序链表 给你一个链表数组,每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中,返回合并后的链表。 正文 这道题有多种解决方案 堆 比较容易,又比较直观的就是堆排序,将每个节点加入最小根堆中&…...
tp6上传文件大小超过了最大值+验证文件上传大小和格式函数
问题: 最近用tp6的文件上传方法上传文件时报文件过大错误。如下所示: $file $this->request->file(file);{"code": 1,"msg": "上传文件大小超过了最大值!","data": {"code": 1,&q…...
解决 Mac 只显示文件大小,不显示目录大小
前言 在使用 mac 的时候总是只显示文件的大小,不显示文件夹的大小,为了解决问题可以开启“计算文件夹”。 步骤 1.进入访达 2.工具栏点击“显示”选项,点击 “查看显示选项” 3.勾选 显示“资源库"文件夹 和 计算所有大小 或者点击…...
分布式大语言模型服务引擎vLLM论文解读
论文地址:Efficient Memory Management for Large Language Model Serving with PagedAttention 摘要 大语言模型(LLMs)的高吞吐量服务需要一次对足够多的请求进行批处理。然而,现有系统面临困境,因为每个请求的键值…...
快速入门——Vue框架快速上手
学习自哔哩哔哩上的“刘老师教编程”,具体学习的网站为:8.Vue框架快速上手_哔哩哔哩_bilibili,以下是看课后做的笔记,仅供参考。 第一节:前端环境准备 编码工具VSCode【www.code.visualstudio.com】/WebStorm也可&am…...
机器学习,我们主要学习什么?
机器学习的发展历程 机器学习的发展历程,大致分为以下几个阶段: 1. 起源与早期探索(20世纪40年代-60年代) 1949年:Hebb提出了基于神经心理学的学习机制,开启了机器学习的先河1950年代:机器学习的…...
安卓burp抓包,bypass ssl pinning
好久好久没有发东西了。主要是懒。。。 这几天在搞apk渗透,遇到了burp无法抓包问题,觉得可以写下来。 问题描述 1. 一台安卓手机,装了面具,可以拿到root 2. 电脑上有burp,设置代理 3.手机和电脑连同一个网段&…...
【如何基于Debian构建Kali Linux】
如何基于Debian构建Kali Linux 修改apt源获取Kali的apt密钥更新并安装Kali Linux软件包添加非root用户 在Linux系统的应用领域中,Kali Linux因其在渗透测试、安全审计等方面的出色表现而备受关注。Kali Linux是一个基于Debian的Linux发行版。接下来,将介…...
Hopper架构 GEMM教程
一 使用 1.1 makefile compile:nvcc -arch=sm_90a -lcuda -lcublas -std=c++17 matmul_h100_optimal.cu -o testrun:./test加入-lcublas,不然会有函数无法被识别 二 代码分析 2.1 kernel外参数分析 2.1.1 基本参数 constexpr int BM = 64*2;constexpr int BN = 256;cons…...
CV -- 基于GPU版CUDA环境+Pycharm YOLOv8 目标检测
目录 下载 CUDA 下载 cuDNN 下载 anaconda 安装 PyTorch pycharm 搭配 yolo 环境并运行 阅读本文须知,需要电脑中有 Nvidia 显卡 下载 CUDA 打开 cmd ,输入 nvidia-smi ,查看电脑支持 CUDA 版本: 我这里是12.0,进入…...
ELK8.17部署(Ubantu24x64)
检查java环境 ELK8.x不支持java8 若无环境可执行 sudo apt install openjdk-17-jre-headless 准备安装包 官网下载地址: ELK products 搜Elasticsearch、Kibana、Logstash、Filebeat versions需一致,这里使用8.17.0 Elasticsearch Kibana Logstash Filebeat e…...
Python glob模块使用示例代码
Python 的 glob 模块位于标准库中,专门用于在文件系统中进行 文件路径模式匹配(与 Shell 中的通配符匹配类似)。它可以根据 通配符(如 *、? 和 [])来查找符合条件的文件路径。 1. glob 模块的核心功能 路径模式匹配:根据指定的通配符模式,匹配对应的文件路径。递归搜索…...
npm、pnpm和yarn有什么区别
1. 性能和速度 npm:在较早的版本中,速度较慢,尤其是在安装大型依赖集时。自npm 5以后的版本引入了缓存机制,性能有所提升。yarn:由Facebook开发,主要目标是提高安装速度。使用了缓存和并行安装(…...
Java 基础面试
final、finalize 和 finally 的不同之处? Final:是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不 能被改变。Finalize:方法是在对象被回收之前调用的方法, 给对象…...
盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案
一、TRS收益互换的本质与业务逻辑 (一)概念解析 TRS(Total Return Swap)收益互换是一种金融衍生工具,指交易双方约定在未来一定期限内,基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...
Python ROS2【机器人中间件框架】 简介
销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
