【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:方法是在对象被回收之前调用的方法, 给对象…...
Linux应用开发之网络套接字编程(实例篇)
服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
剑指offer20_链表中环的入口节点
链表中环的入口节点 给定一个链表,若其中包含环,则输出环的入口节点。 若其中不包含环,则输出null。 数据范围 节点 val 值取值范围 [ 1 , 1000 ] [1,1000] [1,1000]。 节点 val 值各不相同。 链表长度 [ 0 , 500 ] [0,500] [0,500]。 …...
Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
【2025年】解决Burpsuite抓不到https包的问题
环境:windows11 burpsuite:2025.5 在抓取https网站时,burpsuite抓取不到https数据包,只显示: 解决该问题只需如下三个步骤: 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
