以下是一个实现,可以发送和接收任意类型的结构体消息,而不仅限于特定的CustomMsg类型:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>// 通用消息结构体模板
// 要求: 所有消息结构体的第一个字段必须是long类型的mtype
#define MSG_HEADER long mtype// 消息队列配置
#define MSG_QUEUE_KEY 0x1234  // 自定义消息队列键值// 错误处理宏
#define ERROR_EXIT(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)// 创建消息队列
int create_message_queue(key_t key) {int msgid;// 创建消息队列 (IPC_CREAT | IPC_EXCL | 0666)if ((msgid = msgget(key, IPC_CREAT | IPC_EXCL | 0666)) == -1) {if (errno == EEXIST) {// 如果已存在,则直接获取msgid = msgget(key, 0666);if (msgid == -1) {ERROR_EXIT("msgget failed to get existing queue");}} else {ERROR_EXIT("msgget failed to create new queue");}}return msgid;
}// 发送任意结构体消息
// msg: 指向包含MSG_HEADER的结构体指针
// msg_size: 结构体总大小
void send_struct_message(int msgid, void *msg, size_t msg_size) {// 计算实际数据大小 (减去mtype的大小)size_t data_size = msg_size - sizeof(long);if (msgsnd(msgid, msg, data_size, IPC_NOWAIT) == -1) {ERROR_EXIT("msgsnd failed");}printf("Sent %zu byte message (type %ld)\n", msg_size, ((long*)msg)[0]);
}// 接收任意结构体消息
// msg: 指向包含MSG_HEADER的结构体指针
// msg_size: 结构体总大小
// msg_type: 期望接收的消息类型
void receive_struct_message(int msgid, void *msg, size_t msg_size, long msg_type) {// 计算实际数据大小 (减去mtype的大小)size_t data_size = msg_size - sizeof(long);ssize_t bytes = msgrcv(msgid, msg, data_size, msg_type, 0);if (bytes == -1) {ERROR_EXIT("msgrcv failed");}printf("Received %zd byte message (type %ld)\n", bytes + sizeof(long), ((long*)msg)[0]);
}// 删除消息队列
void remove_message_queue(int msgid) {if (msgctl(msgid, IPC_RMID, NULL) == -1) {if (errno != EIDRM) { // 忽略已删除的错误perror("msgctl IPC_RMID failed");}}
}// ===================== 使用示例 =====================// 示例消息结构体1
typedef struct {MSG_HEADER;  // 必须作为第一个字段int sensor_id;float temperature;float humidity;unsigned long timestamp;
} SensorData;// 示例消息结构体2
typedef struct {MSG_HEADER;  // 必须作为第一个字段char device_name[16];int state;int error_code;float voltage;float current;
} DeviceStatus;// 示例消息结构体3
typedef struct {MSG_HEADER;  // 必须作为第一个字段short x;short y;short z;unsigned char accuracy;
} MotionData;int main() {int msgid = create_message_queue(MSG_QUEUE_KEY);pid_t pid = fork();if (pid < 0) {ERROR_EXIT("fork failed");}if (pid > 0) { // 父进程 - 发送者// 给接收者时间启动sleep(1);// 发送SensorData消息SensorData sensor_msg = {.mtype = 1,.sensor_id = 101,.temperature = 25.6f,.humidity = 45.7f,.timestamp = 1234567890};send_struct_message(msgid, &sensor_msg, sizeof(SensorData));// 发送DeviceStatus消息DeviceStatus device_msg = {.mtype = 2,.device_name = "Main Controller",.state = 1,.error_code = 0,.voltage = 3.3f,.current = 0.75f};send_struct_message(msgid, &device_msg, sizeof(DeviceStatus));// 发送MotionData消息MotionData motion_msg = {.mtype = 3,.x = 1024,.y = -512,.z = 256,.accuracy = 95};send_struct_message(msgid, &motion_msg, sizeof(MotionData));// 等待接收者处理sleep(1);// 删除消息队列remove_message_queue(msgid);} else { // 子进程 - 接收者// 接收SensorData消息SensorData recv_sensor;receive_struct_message(msgid, &recv_sensor, sizeof(SensorData), 1);printf("SensorData: ID=%d, Temp=%.1f°C, Hum=%.1f%%, Time=%lu\n",recv_sensor.sensor_id, recv_sensor.temperature,recv_sensor.humidity, recv_sensor.timestamp);// 接收DeviceStatus消息DeviceStatus recv_device;receive_struct_message(msgid, &recv_device, sizeof(DeviceStatus), 2);printf("DeviceStatus: Name='%s', State=%d, Error=%d, V=%.2fV, I=%.2fA\n",recv_device.device_name, recv_device.state,recv_device.error_code, recv_device.voltage, recv_device.current);// 接收MotionData消息MotionData recv_motion;receive_struct_message(msgid, &recv_motion, sizeof(MotionData), 3);printf("MotionData: X=%d, Y=%d, Z=%d, Accuracy=%d%%\n",recv_motion.x, recv_motion.y, recv_motion.z, recv_motion.accuracy);}return EXIT_SUCCESS;
}
  1. 消息队列限制

    • 使用msgctl(IPC_STAT)检查队列状态

    • 监控队列使用情况,避免溢出

这个实现提供了高度灵活的消息传递机制,适用于各种嵌入式场景,从简单的传感器数据采集到复杂的设备控制命令,都可以通过定义适当的结构体来实现高效通信。

=========================阻塞和非阻塞接收方式===============================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <stdbool.h>// 通用消息头要求
#define MSG_HEADER long mtype// 消息队列配置
#define MSG_QUEUE_KEY 0x1234// 错误处理宏
#define ERROR_EXIT(msg) do { perror(msg); exit(EXIT_FAILURE); } while(0)// 创建消息队列
int create_message_queue(key_t key) {int msgid = msgget(key, IPC_CREAT | 0666);if (msgid == -1) {ERROR_EXIT("msgget failed");}return msgid;
}// 发送任意结构体消息(阻塞)
void send_struct_message(int msgid, void *msg, size_t msg_size) {size_t data_size = msg_size - sizeof(long);if (msgsnd(msgid, msg, data_size, 0) == -1) {  // 阻塞发送ERROR_EXIT("msgsnd failed");}printf("Sent %zu byte message (type %ld)\n", msg_size, ((long*)msg)[0]);
}// 阻塞接收任意结构体消息
bool receive_struct_message_blocking(int msgid, void *msg, size_t msg_size, long msg_type) {size_t data_size = msg_size - sizeof(long);ssize_t bytes = msgrcv(msgid, msg, data_size, msg_type, 0);if (bytes == -1) {return false;}printf("Received %zd byte message (type %ld) [blocking]\n", bytes + sizeof(long), ((long*)msg)[0]);return true;
}// 非阻塞接收任意结构体消息
bool receive_struct_message_nonblocking(int msgid, void *msg, size_t msg_size, long msg_type) {size_t data_size = msg_size - sizeof(long);ssize_t bytes = msgrcv(msgid, msg, data_size, msg_type, IPC_NOWAIT);if (bytes == -1) {if (errno == ENOMSG) {// 没有消息不是错误,只是需要重试return false;}ERROR_EXIT("msgrcv failed");}printf("Received %zd byte message (type %ld) [non-blocking]\n", bytes + sizeof(long), ((long*)msg)[0]);return true;
}// 带超时的接收(混合模式)
bool receive_struct_message_timeout(int msgid, void *msg, size_t msg_size, long msg_type, int timeout_sec) {for (int i = 0; i < timeout_sec * 10; i++) {if (receive_struct_message_nonblocking(msgid, msg, msg_size, msg_type)) {return true;}// 等待100ms后重试usleep(100 * 1000);}return false;
}// 删除消息队列
void remove_message_queue(int msgid) {if (msgctl(msgid, IPC_RMID, NULL) == -1 && errno != EIDRM) {perror("msgctl IPC_RMID failed");}
}// ===================== 使用示例 =====================typedef struct {MSG_HEADER;int counter;char data[64];
} TestMessage;int main() {int msgid = create_message_queue(MSG_QUEUE_KEY);pid_t pid = fork();if (pid < 0) {ERROR_EXIT("fork failed");}if (pid > 0) { // 父进程 - 发送者sleep(1);  // 等待接收者准备// 发送3条消息for (int i = 1; i <= 3; i++) {TestMessage msg = {.mtype = 1,.counter = i,.data = "Blocking test"};send_struct_message(msgid, &msg, sizeof(TestMessage));sleep(1);}// 发送快速连续消息for (int i = 4; i <= 6; i++) {TestMessage msg = {.mtype = 2,.counter = i,.data = "Non-blocking test"};send_struct_message(msgid, &msg, sizeof(TestMessage));}// 等待接收者处理sleep(2);remove_message_queue(msgid);} else { // 子进程 - 接收者// 1. 阻塞接收演示printf("=== Blocking Receive Test ===\n");for (int i = 0; i < 3; i++) {TestMessage msg;if (receive_struct_message_blocking(msgid, &msg, sizeof(TestMessage), 1)) {printf("Blocking received: counter=%d, data=%s\n", msg.counter, msg.data);}}// 2. 非阻塞接收演示printf("\n=== Non-blocking Receive Test ===\n");int received = 0;while (received < 3) {TestMessage msg;if (receive_struct_message_nonblocking(msgid, &msg, sizeof(TestMessage), 2)) {printf("Non-blocking received: counter=%d, data=%s\n", msg.counter, msg.data);received++;} else {printf("No message available, doing other work...\n");sleep(1); // 模拟其他工作}}// 3. 超时接收演示printf("\n=== Timeout Receive Test ===\n");TestMessage msg;if (receive_struct_message_timeout(msgid, &msg, sizeof(TestMessage), 3, 2)) {printf("Received message within timeout\n");} else {printf("Timeout waiting for message (type 3)\n");}}return EXIT_SUCCESS;
}

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

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

相关文章

TCP的三次握手和四次挥手实现过程。以及为什么需要三次握手?四次挥手?

三次握手和四次挥手的实现原理&#xff0c;以及为什么要这样设计&#xff1f;三次握手的实现三次握手的核心角色与参数三次握手的具体步骤第一步&#xff1a;客户端 → 服务器&#xff08;发送 SYN 报文&#xff09;第二步&#xff1a;服务器 → 客户端&#xff08;发送 SYNACK…

Java开发时出现的问题---架构与工程实践缺陷

除语言和并发层面&#xff0c;代码设计、工程规范的缺陷更易导致系统扩展性差、维护成本高&#xff0c;甚至引发线上故障。1. 面向对象设计的常见误区过度继承与脆弱基类&#xff1a;通过继承复用代码&#xff08;如class A extends B&#xff09;&#xff0c;会导致子类与父类…

项目评审管理系统(源码+文档+讲解+演示)

引言 在当今快速发展的商业环境中&#xff0c;项目评审和管理是确保项目成功的关键环节。项目评审管理系统作为一种创新的数字化工具&#xff0c;通过数字化手段优化项目评审和管理的全流程&#xff0c;提高项目管理效率&#xff0c;降低风险&#xff0c;提升项目成功率。本文将…

ComfyUI 安装WanVideoWrapper

目录 方法2&#xff1a;通过 ComfyUI-Manager 安装 方法3&#xff1a;手动下载并解压 测试代码&#xff1a; WanVideoWrapper 方法2&#xff1a;通过 ComfyUI-Manager 安装 在 ComfyUI 界面顶部找到 Manager&#xff08;管理器&#xff09;选项。 进入 Install Custom Nod…

react合成事件大全,如onClick,onDrag

1. 鼠标事件onClick - 点击事件onContextMenu - 右键菜单事件onDoubleClick - 双击事件onDrag - 拖拽事件onDragEnd - 拖拽结束事件onDragEnter - 拖拽进入目标区域事件onDragExit - 拖拽离开目标区域事件onDragLeave - 拖拽离开事件onDragOver - 拖拽悬停事件onDragStart - 拖…

从《中国开源年度报告》看中国开源力量的十年变迁中,Apache SeaTunnel 的跃迁

如果把开源世界比作一条奔涌的大河&#xff0c;过去十年里&#xff0c;中国开发者已经从“岸边试水”变成了“中流击水”。在最近落下帷幕的 Community Over Code Asia 2025&#xff0c;华东师范大学教授王伟老师基于《中国开源年度报告》进行的一场分享&#xff0c;用一组数字…

JAVA 程序员cursor 和idea 结合编程

cursor 是基于vscode改良而来的&#xff0c;外加上Claude大语言模型而产生的AI编辑器&#xff0c;市面上也有阿里的灵码qianwen3-coder大语言模型。我个人电脑还是喜欢用idea集成灵码插件开发。但是也稍微介绍下习惯idea的人只是使用cursor代码生成的话&#xff0c;这有个小妙招…

查看部署在K8S服务的资源使用情况

要查看 Pod中 server 的资源使用情况&#xff08;CPU 和内存&#xff09;&#xff0c;你需要使用 Kubernetes 的监控工具。最常用的是 kubectl top 命令。✅ 方法一&#xff1a;使用 kubectl top&#xff08;推荐&#xff09; 1. 查看 Pod 的 CPU 和内存使用 kubectl top pod s…

uni-app vue3 小程序接入 aliyun-rtc-wx-sdk

安装依赖&#xff1a; npm install aliyun-rtc-wx-sdk crypto-jsuni-app&#xff0c;新建一个页面&#xff0c;粘贴以下代码 在阿里云实时音视频补充appId、appKey即可&#xff0c; <template><view class"container"><!-- 用户输入区域 --><vi…

Java技术栈/面试题合集(3)-Java并发篇

场景 Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享: Java入门、进阶、强化、扩展、知识体系完善等知识点学习、性能优化、源码分析专栏分享_java高级进阶-CSDN博客 通过对面试题进行系统的复习可以对Java体系的知识点进行查漏补缺。…

[AI 生成] Spark 面试题

spark 基础问题面试题以下是 Spark 基础面试题的全面梳理&#xff0c;涵盖核心概念、架构原理和编程模型&#xff0c;帮助快速掌握高频考点&#xff1a;一、核心概念1. Spark 核心组件组件作用Driver执行 main() 方法&#xff0c;调度任务&#xff0c;管理集群资源Executor在 W…

MySQL的DML增删改操作:

目录 添加数据&#xff1a; 方式1&#xff1a;一条一条添加数据&#xff1a; 方式2&#xff1a;将查询结果插入到表中&#xff1a; 更新数据&#xff1a; 删除数据&#xff1a; MySQL8的新特性&#xff1a;计算列&#xff1a; 本文介绍了MySQL数据库操作语言(DML)的基本使…

MySQL运维常用语法速查

&#x1f5c3;️ 一、数据库操作 CREATE DATABASE db_name; USE db_name; DROP DATABASE db_name; SHOW DATABASES;&#x1f517; 官方文档 &#x1f4ca; 二、表操作 表创建示例 CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,name VARCHAR(50) NOT NULL,email V…

汽车以太网通信协议——SOME/IP

1. 背景 SOME/IP是一种汽车中间件解决方案&#xff0c;其全称是Scalable Service-Oriented Middleware over IP&#xff0c;即位于 IP 协议层以上的一种面向服务的可扩展的中间件。 中间件&#xff1a;该术语起源于复杂的软件系统开发&#xff0c;用以实现软件组件之间的数据交…

什么是负载均衡,有哪些常见算法?

文章目录1.什么是负载均衡2.负载均衡的分类2.1 二层负载均衡2.2 三层负载均衡2.3 四层负载均衡2.4 七层负载均衡3.负载均衡工具3.1 LVS3.2 Nginx3.3 HAProxy4.常见负载均衡算法5.面试回答模板1.什么是负载均衡 为了提升web应用的各方面能力&#xff0c;我们一般会把多台机器组…

PyTorch 核心三件套:Tensor、Module、Autograd

欢迎来到啾啾的博客&#x1f431;。 记录学习点滴。分享工作思考和实用技巧&#xff0c;偶尔也分享一些杂谈&#x1f4ac;。 有很多很多不足的地方&#xff0c;欢迎评论交流&#xff0c;感谢您的阅读和评论&#x1f604;。 目录引言1 Tensor1.1 &#x1f6e0;️Tensor 的核心用…

python源码是如何运行起来的

为什么要了解底层原理 写出高质量代码 问题定位 满足好奇心 机械通感 开始 当我们编写并运行一行 print(Hello, World!) 时&#xff0c;背后究竟发生了什么&#xff1f;Python 代码是如何从我们可读的文本&#xff0c;变成计算机可以执行的指令的呢&#xff1f; 很多人将…

MacOS Docker 安装指南

MacOS Docker 安装指南 引言 Docker 是一个开源的应用容器引擎,它允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。Docker …

Cisco 3750X交换机更新到IOS 15.2后无法启动 提示:Boot process failed...

背景及故障现象 一台新购入的二手Cisco 3750X-48P&#xff0c;原机自带IOS软件版本为12.x&#xff0c;可以正常工作。 但将IOS版本升级到15.2之后&#xff0c;在启动过程中卡住。 第一次加载IOS软件时是正常的&#xff0c;提示&#xff1a; Loading "flash:/c3750e-uni…

Redis Redis 常见数据类型

Redis 提供了 5 种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维非常重要&#xff0c;同时掌握每种数据结构的常见命令&#xff0c;会在使用 Redis 的时候做到游刃有余。 一、预备知识 官方文档&#xff1a;Commands | Docs (redis.io) 1、最核心的两个命令…