Posix消息队列传递结构体时始终报“消息过长”错误求助
Posix消息队列“消息过长”错误排查
我在Kubuntu 22.04系统上用C语言开发Posix消息队列程序,需求是启动指定数量的线程等待队列消息(消息为包含已分配内存指针的结构体),最快的线程获取消息并处理;主程序负责启动线程、填充队列,待所有线程完成后展示结果。但程序始终报“消息过长”错误。
简化代码后问题依旧,目前我的理解:
- 消息队列已设置最大消息大小为
sizeof(message_t); - 发送时直接传入自定义结构体,指定长度为
sizeof(message_t); - 接收时告知
mq_receive读取大小为sizeof(message_t)。
发送操作正常,发送一条消息后,/dev/mqueue/test-123显示QSIZE为70(对应结构体50+20的大小),符合预期。想请教:是否遗漏了配置?结构体不能直接放入消息队列吗?另外,因为是父进程和线程间通信,我认为共享地址是安全的。
简化后的代码如下:
#include <pthread.h> #include <mqueue.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> typedef struct message { //long int message_type; char path[50]; char name[20]; } message_t; int main(int argc, char *argv[]) { const char* queue_name = "/test-123"; // Message Queue File Descriptor for Sending mqd_t msgq_fd ; // Attributes of the Message queue struct mq_attr attr = { 0 }; attr.mq_maxmsg = 100; attr.mq_msgsize = sizeof(message_t); // (Create and) open the message Queue for Writing only if((msgq_fd = mq_open(queue_name, O_RDWR | O_CREAT, 0660, &attr)) == -1) { perror("Sender: mq_open failed"); exit(4); } //Put 5 Messages into the Message queue for(int i=0; i < 5; i++) { message_t *msg = calloc(1,sizeof(message_t)); strcpy(msg->name,"test"); strcpy(msg->path,"testpath"); printf("Message %d prepared...", i); // Error Sending if(mq_send(msgq_fd, (const char *)msg, sizeof(message_t), 0) == -1) { perror("Sender: unable to send message"); mq_close(msgq_fd); exit(10); } printf("queued\n"); sleep(1); } printf("\nReading messages from Queue\n"); int ret = 0; // Struct for storing the message from the Message Queue message_t recv_msg; // Read 5 messages from the Message Queue for(int i=0; i < 5; i++) { printf("Message %d:\n",i+1); sleep(1); ret = mq_receive(msgq_fd,(char*)&recv_msg,sizeof(attr.mq_msgsize),NULL); // Error receiving if(ret == -1) { //printf("%d, %p, %ld\n",msgq_fd2, &recv_msg, sizeof(message_t)); perror("Message receive error"); } // Print the content of the received message printf("%s/%s\n\n",recv_msg.path,recv_msg.name); } return 0; }
问题根源与修复
核心错误
你遇到的“消息过长”错误,本质是**mq_receive调用时传入的缓冲区大小参数错误**。
看代码中的接收逻辑:
ret = mq_receive(msgq_fd,(char*)&recv_msg,sizeof(attr.mq_msgsize),NULL);
这里的sizeof(attr.mq_msgsize)是取mq_attr结构体中mq_msgsize字段的字节数(64位系统中为8字节,因为它是long int类型),而非你设置的实际消息大小attr.mq_msgsize。这导致mq_receive认为缓冲区仅8字节,远小于实际消息的70字节,因此触发错误。
修复方法
将接收时的缓冲区大小参数改为attr.mq_msgsize或直接sizeof(message_t)即可:
// 两种写法二选一 ret = mq_receive(msgq_fd,(char*)&recv_msg, attr.mq_msgsize, NULL); // 或者 ret = mq_receive(msgq_fd,(char*)&recv_msg, sizeof(message_t), NULL);
额外注意事项
- 结构体指针问题:如果原始代码中结构体包含内存指针,即使是父子线程间通信,也不能直接把指针放入消息队列。指针是进程虚拟地址空间内的标识,若后续扩展为跨进程通信会直接失效;且若发送方释放指针指向的内存,接收方使用时会触发内存错误。正确做法是将指针指向的数据直接嵌入结构体(如简化代码中的数组),或序列化数据后发送。
- 资源清理:程序结束时需调用
mq_close(msgq_fd)关闭队列描述符,再调用mq_unlink(queue_name)删除队列对象,避免系统残留无用资源。 - 权限检查:创建队列时设置的
0660权限需确保符合实际访问需求,避免后续出现权限拒绝问题。
内容的提问来源于stack exchange,提问作者Basti
相关产品推荐
相关产品推荐

