linux 下消息队列

news/2025/3/17 9:44:42/

文章目录

  • 📨 Linux System V 消息队列实战
    • 一、消息队列核心概念 💡
      • 1. 消息队列特点 🌟
      • 2. 生命周期 🔄
    • 二、项目概述
    • 三、完整代码实现
      • 1. 公共头文件 `common.hpp`
      • 2. 发送端 `sender.cpp`
      • 3. 接收端 `receiver.cpp`
    • 三、编译与运行指南
      • 1. 编译命令
      • 2. 运行顺序
    • 四、代码分解与核心函数 🛠️
      • 1. 公共头文件 `common.hpp` 📁
        • 消息结构体定义
        • Key 生成与队列创建
        • 封装函数
      • 2. 发送端代码解析 📤
        • 关键点 🔑
      • 3. 接收端代码解析 📥
        • 关键点 🔍
    • 五、常见问题与调试技巧 🚨
      • 1. 系统命令 💻

在这里插入图片描述


📨 Linux System V 消息队列实战


一、消息队列核心概念 💡

1. 消息队列特点 🌟

  • 📦 结构化数据:消息包含类型标识(mytype)和正文(data),支持分类处理
  • 异步通信:发送方和接收方无需同时在线
  • 🔒 持久性:消息队列在内核中持久存在,直到显式删除
  • 🔑 访问控制:通过权限标志(如0666)管理读写权限

2. 生命周期 🔄

  • 创建发送/接收销毁
  • ❗若不主动销毁,队列会持续占用内核资源(通过ipcs -q可查看)

二、项目概述

本示例通过 System V 消息队列 实现跨进程通信,包含三个核心文件:

  • common.hpp:消息队列公共配置
  • sender.cpp:消息生产者(发送端)
  • receiver.cpp:消息消费者(接收端)

三、完整代码实现

1. 公共头文件 common.hpp

#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <cstring>
#include <cstdlib>// 消息队列标识配置
const char* pathname = "/home"; // ftok路径参数(需真实存在)
const int proj_id = 666;        // 项目ID(取值范围0-255)// 消息结构体(必须包含long类型字段)
struct message {long mytype;    // 消息类型标识(必须 > 0)char data[100]; // 消息正文(最大99字符)
};// 错误码枚举
enum {MSGGET_ERROR = 1,
};// 通用队列创建/获取函数
int Msgqueue(int flag) {key_t key = ftok(pathname, proj_id);if (key < 0) {perror("ftok failed");exit(MSGGET_ERROR);}int msgid = msgget(key, flag);if (msgid < 0) {perror("msgget failed");exit(MSGGET_ERROR);}return msgid;
}// 创建新队列(服务端)
int CreateMsg() {return Msgqueue(IPC_CREAT | IPC_EXCL | 0666);
}// 获取已有队列(客户端)
int Getmsg() {return Msgqueue(IPC_CREAT | 0666);
}

2. 发送端 sender.cpp

#include "common.hpp"int main() {// 创建消息队列int msgid = CreateMsg();std::cout << " 消息队列创建成功! ID: " << msgid << std::endl;// 构造消息message msg;msg.mytype = 1; // 消息类型标识snprintf(msg.data, sizeof(msg.data), "hello from sender");// 发送消息(阻塞模式)if (msgsnd(msgid, &msg, sizeof(msg.data), 0) < 0) {perror(" 消息发送失败");exit(1);}std::cout << " 消息已发送: " << msg.data << std::endl;return 0;
}

3. 接收端 receiver.cpp

#include "common.hpp"int main() {// 获取消息队列int msgid = Getmsg();std::cout << " 连接到消息队列 ID: " << msgid << std::endl;// 接收消息(阻塞等待类型为1的消息)message msg;if (msgrcv(msgid, &msg, sizeof(msg.data), 1, 0) < 0) {perror(" 消息接收失败");exit(1);}std::cout << " 收到消息: " << msg.data << std::endl;// 销毁队列(生产环境慎用!)if (msgctl(msgid, IPC_RMID, nullptr) < 0) {perror(" 队列删除失败");} else {std::cout << "消息队列已销毁" << std::endl;}return 0;
}

三、编译与运行指南

1. 编译命令

# 生成发送端可执行文件
g++ sender.cpp -o sender -std=c++11# 生成接收端可执行文件
g++ receiver.cpp -o receiver -std=c++11

2. 运行顺序

# 终端1:运行发送端(创建队列)
./sender# 终端2:运行接收端(消费消息)
./receiver

在这里插入图片描述

四、代码分解与核心函数 🛠️

1. 公共头文件 common.hpp 📁

消息结构体定义
struct message {long mytype;    // 🔢 消息类型(必须 > 0)char data[100]; // 📝 消息正文(最大长度可调整)
};
Key 生成与队列创建
key_t key = ftok(pathname, proj_id); // 🗝️ 生成唯一键值
int msgid = msgget(key, flag);       // 🚪 创建/获取队列
  • ftok参数
    • 📂 pathname:任意存在的文件路径(本文使用/home
    • 🆔 proj_id:项目标识符(确保不同应用使用不同值)
封装函数
  • 🆕 CreateMsg():创建新队列(IPC_CREAT | IPC_EXCL确保唯一性)
  • 🔍 Getmsg():获取已有队列(若不存在则创建)

2. 发送端代码解析 📤

int main() {int msgid = CreateMsg(); // 🏗️ 创建队列message msg;msg.mytype = 1; // 🏷️ 设置消息类型snprintf(msg.data, sizeof(msg.data), "hello from sender\n");// ✈️ 发送消息(阻塞模式)msgsnd(msgid, &msg, sizeof(msg.data), 0); std::cout << "Message sent: " << msg.data << std::endl;return 0;
}
关键点 🔑
  • 🎯 消息类型:接收端通过mytype筛选消息
  • 🚦 发送模式
    • 🛑 0:阻塞发送(队列满时等待)
    • 🚀 IPC_NOWAIT:非阻塞发送(立即返回错误)

3. 接收端代码解析 📥

int main() {int msgid = Getmsg(); // 🔍 获取队列message msg;// 📭 接收类型为1的消息(阻塞模式)msgrcv(msgid, &msg, sizeof(msg.data), 1, 0); std::cout << msg.data << std::endl;msgctl(msgid, IPC_RMID, NULL); // 🗑️ 销毁队列return 0;
}
关键点 🔍
  • 🎯 消息过滤msgrcv的第4个参数指定接收的消息类型
    • 🎯 1:仅接收类型为1的消息
    • 🎲 0:接收队列中第一条消息
    • 🔍 -3:接收类型 ≤3 的最小消息
  • 🧹 资源释放IPC_RMID立即删除队列

五、常见问题与调试技巧 🚨

1. 系统命令 💻

ipcs -q          # 🔍 查看所有消息队列
ipcrm -q <msqid> # 🗑️ 手动删除队列

http://www.ppmy.cn/news/1579778.html

相关文章

初探 Threejs 物理引擎CANNON,解锁 3D 动态魅力

简介 Cannon.js 是一个基于 JavaScript 的物理引擎&#xff0c;它可以在浏览器中模拟物理效果。它支持碰撞检测、刚体动力学、约束等物理效果&#xff0c;可以用于创建逼真的物理场景和交互。 参考文档 官方示例 原理 Cannon.js 使用了欧拉角来表示物体的旋转&#xff0c;…

【误差理论与可靠性工程】可靠性工程基本理论

可靠性工程是一种工程学科&#xff0c;主要涉及如何对产品和系统的可靠性进行评估、设计和管理等。可靠性工程的基本理论包括可靠性的定义、可靠性的特征、可靠性的评估方法、可靠性的设计原则和可靠性预测方法等。 1. 可靠性的定义 可靠性是指产品或系统在规定条件下保持正常…

1.5.3 掌握Scala内建控制结构 - for循环

Scala的for循环功能强大&#xff0c;支持单重和嵌套循环。单重for循环语法为for (变量 <- 集合或数组 (条件)) {语句组}&#xff0c;可选筛选条件&#xff0c;循环变量依次取集合值。支持多种任务&#xff0c;如输出指定范围整数&#xff08;使用Range、to、until&#xff0…

DeepSeek:技术教育领域的AI变革者——从理论到实践的全面解析

一、技术教育为何需要DeepSeek&#xff1f; 在数字化转型的浪潮下&#xff0c;技术教育面临着知识更新快、实践门槛高、个性化需求强三大核心挑战。传统的教学模式难以满足开发者快速掌握前沿技术、构建复杂系统能力的需求。DeepSeek作为国产开源大模型的代表&#xff0c;凭借…

一周学会Flask3 Python Web开发-SQLAlchemy查询所有数据操作-班级模块

锋哥原创的Flask3 Python Web开发 Flask3视频教程&#xff1a; 2025版 Flask3 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们来新建一个的蓝图模块-班级模块&#xff0c;后面可以和学生模块&#xff0c;实现一对多的数据库操作。 blueprint下新建g…

深入探讨PHP的协程:实现高并发的编程模型

深入探讨PHP的协程&#xff1a;实现高并发的编程模型 引言 在现代Web开发中&#xff0c;高并发处理能力是衡量一个系统性能的重要指标。传统的同步阻塞I/O模型在处理大量并发请求时&#xff0c;往往会导致资源浪费和性能瓶颈。为了解决这一问题&#xff0c;协程&#xff08;C…

3月16号

今天学了一些java的相关知识: Scanner in new Scanner(System.in);//这个是java中输入必备的一条语句int n0;//对n初始化 nin.nextInt();//输入n的值 double x0;//浮点数 xin.nextDouble();//浮点数的输入int[] numbersnew int[100];//定义数组,并且数组大小为100 numbers[0]…

简单以太网配置

display arp //查看路由器mac地址 交换机配置命令&#xff1a; system-view // 从用户视图进入系统视图 dis mac-address //查看mac地址表 路由器配置命令: system-view // 从用户视图进入系统视图 int GigabitEthernet 0/0/0 //进入G口 0/0/0 进入之后配置网关: ip addre…