C语言SysV消息队列无法读取全部消息问题求助
问题分析与解决方案
核心错误:消息长度参数传递错误
你的代码中,msgsnd和msgrcv的第三个参数(消息长度)使用了整个结构体的大小sizeof(messages[i])/sizeof(msg),这不符合System V消息队列的API规范:
msgsnd要求msg_len是消息正文的长度(即结构体中msg_type之后的部分,不包含msg_type本身)。msgrcv的第三个参数是接收缓冲区中用于存储正文的最大长度,同样应该匹配正文的实际大小。
错误的长度参数会导致:
msgsnd向队列写入超出结构体范围的内存数据(未定义行为),破坏消息结构。msgrcv尝试读取的长度与队列中存储的消息正文长度不匹配,导致后续读取失败。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ipc.h> #include <sys/msg.h> #include <sys/types.h> // Define a structure for our messages struct message { long msg_type; char msg_text[100]; }; int main() { key_t key; int msg_id; struct message msg; // Generate a key for the message queue key = ftok("progfile", 'A'); if (key == -1) { perror("ftok failed"); exit(EXIT_FAILURE); } // Create the message queue msg_id = msgget(key, 0666 | IPC_CREAT); if (msg_id == -1) { perror("msgget failed"); exit(EXIT_FAILURE); } // Prepare messages to send struct message messages[3] = {{1, "This is message with priority 1"}, {2, "This is message with priority 2"}, {3, "This is message with priority 3"}}; // Calculate message text length (excluding msg_type) size_t msg_text_len = sizeof(msg.msg_text); // Send the messages for (int i = 0; i < 3; i++) { if (msgsnd(msg_id, &messages[i], msg_text_len, 0) == -1) { perror("msgsnd failed"); exit(EXIT_FAILURE); } } // Receive the messages for (int i = 1; i <= 3; i++) { memset(&msg, 0, sizeof(msg)); ssize_t recv_len = msgrcv(msg_id, &msg, msg_text_len, 0, IPC_NOWAIT); if (recv_len != -1) { printf("Received message: %s\n", msg.msg_text); } else { perror("msgrcv failed"); printf("No message in the queue\n"); } } // Destroy the message queue if (msgctl(msg_id, IPC_RMID, NULL) == -1) { perror("msgctl failed"); exit(EXIT_FAILURE); } return 0; }
关键修正点
- 使用
sizeof(msg.msg_text)作为消息长度,确保只传递正文部分。 - 添加了错误检查(
perror),方便排查API调用失败的原因。 - 修复了
printf中的换行符(原代码中是无效的换行,改为\n)。
同进程/跨进程差异的原因
当拆分到两个独立进程时,内存布局的巧合可能让错误的长度参数没有触发严重的未定义行为,消息能被“侥幸”正确读取;但在同一个进程中,msgsnd写入的越界数据会直接破坏消息队列中的后续消息结构,导致msgrcv无法解析剩余消息。
残留消息队列清理
如果之前运行的程序没有正常执行msgctl,可以用以下命令手动清理:
ipcrm -q <msg_id>
(msg_id可以通过ipcs -q命令查看)
内容的提问来源于stack exchange,提问作者Edward Wang
相关产品推荐
相关产品推荐

