linux下實現System V消息隊列實現任意結構體傳輸

以下是一個實現,可以發送和接收任意類型的結構體消息,而不僅限于特定的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、最核心的兩個命令…