【问题标题】:mq_receive returns "Message too long" even though msg_len is greater than mq_msgsize即使 msg_len 大于 mq_msgsize,mq_receive 也会返回“消息太长”
【发布时间】:2021-08-03 10:19:43
【问题描述】:

我正在尝试了解 Linux 中消息队列的工作原理。

最后,我想要一个程序,我可以在不同的线程/进程之间发送和接收东西,但首先,我只创建一个消息队列,并让它阻塞队列中的输入,但是mq_receive() 返回Message too long。

查看文档,这个错误表明`msg_len小于消息队列的mq_msgsize属性。但对我来说不是这样。

对不起,如果我遗漏了一些明显的东西,但我无法弄清楚。

#define MAX_MESSAGES 10
#define MAX_MSG_SIZE 256
#define MSG_BUFFER_SIZE MAX_MSG_SIZE + 10


int main() 
{
     mqd_t qd_server, qd_client;
     char in_buffer [MSG_BUFFER_SIZE];
     char out_buffer [MSG_BUFFER_SIZE];
 
    struct mq_attr attr, tmpAttr;  
    attr.mq_flags = 0;
    attr.mq_maxmsg = MAX_MESSAGES;
    attr.mq_msgsize = MAX_MSG_SIZE;
    attr.mq_curmsgs = 0;
    
    
    if ((qd_server = mq_open ("/sp-example-server", O_RDONLY|O_CREAT, 0644, &attr)) == -1) 
    {
         printf("%s\n", strerror(errno));
    }


    if (mq_getattr(qd_server, &tmpAttr) == -1)
    {
               printf("mq_getattr error");
    }

        printf("Maximum # of messages on queue:   %ld\n", tmpAttr.mq_maxmsg);
        printf("Maximum message size:             %ld\n", tmpAttr.mq_msgsize);


    int iret = mq_receive(qd_server, in_buffer, sizeof(in_buffer), NULL);
    if (iret == -1)
    {   
         printf("%s\n", strerror(errno));
    }
    return 0;
}

编辑:

运行mmq_getattr(qd_server, & tmpAttr) 后,似乎从未设置属性,这可能是原因。现在来看看为什么没有设置属性?

// output:

Maximum # of messages on queue:   10
Maximum message size:             8192

【问题讨论】:

  • 您确定mq_msgsize 是您认为的那样吗?您没有打开队列 O_EXCLusively。 mq_gettattr 说什么?
  • 你是对的,值没有设置,但为什么会这样呢?如果没有O_EXCL,它根本不会创建文件,所以不会填充qd_server?
  • 查找后,如果消息队列已经存在,看起来O_EXCL 在与O_CREAT 一起使用时基本上会中止该功能,但在我的情况下,它是唯一创建的队列并且没有任何先前的
  • “从未设置属性”是什么意思?请向我们展示代码,向我们展示它们的值,并描述您如何知道它们的值是错误的。
  • 您可以看到属性未设置为程序中设置的值

标签: c linux multithreading posix message-queue


【解决方案1】:

您向我们展示的代码并未创建/sp-example-server 消息队列。

相反,某些先前的进程使用您看到的 mq_maxmsg 和 mq_msgsize 的值创建了该队列。如果队列的创建者省略了属性说明——也就是说,将 NULL struct mq_attr * 传递给 mq_open——那么 the implementation will provide default values。在 Linux 上,these defaults match the values you see。

您的代码的一些早期版本称为 mq_open 具有 NULL 属性似乎是合理的,因此 O_CREAT 将队列作为您现在所经历的那样。

为了适应这种情况,您可以重新启动或mq_unlink 队列,强制下一次调用mq_open 重新创建它。更具防御性的是,当您不以 O_EXCLusively 方式打开队列时,然后使用 mq_getattr 验证队列的属性。

【讨论】:

  • 如果/sp-example-server 没有创建,open() 不应该失败吗?你如何验证队列是否是在其他地方创建的?还有没有办法查看已经分配了哪些现有队列?
猜你喜欢
  • 2011-08-03
  • 2017-04-20
  • 2017-11-23
  • 2020-07-19
  • 2020-03-06
  • 1970-01-01
  • 2023-04-10
  • 1970-01-01
  • 2018-02-25
相关资源
最近更新 更多