You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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);

额外注意事项

  1. 结构体指针问题:如果原始代码中结构体包含内存指针,即使是父子线程间通信,也不能直接把指针放入消息队列。指针是进程虚拟地址空间内的标识,若后续扩展为跨进程通信会直接失效;且若发送方释放指针指向的内存,接收方使用时会触发内存错误。正确做法是将指针指向的数据直接嵌入结构体(如简化代码中的数组),或序列化数据后发送。
  2. 资源清理:程序结束时需调用mq_close(msgq_fd)关闭队列描述符,再调用mq_unlink(queue_name)删除队列对象,避免系统残留无用资源。
  3. 权限检查:创建队列时设置的0660权限需确保符合实际访问需求,避免后续出现权限拒绝问题。

内容的提问来源于stack exchange,提问作者Basti

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 06:11:13