【问题标题】:mq_receive: message too longmq_receive: 消息太长
【发布时间】:2011-08-03 07:23:37
【问题描述】:

我正在使用队列实现 2 个进程之间的通信。问题是当我调用函数 mq_receive 时,我得到这个错误:消息太长。

我做了以下事情:

struct mq_attr attr;

long size = attr.mq_msgsize;
.... // initializing the queue "/gateway"

int rc = mq_receive(gateway, buffer, size, &prio);

如果我打印大小值,我得到 size=1,而当我打印相同大小但来自另一个程序(通过相同机制获得)时,我得到的不是长整数(-1217186280)...

我该如何解决这个错误?....所以虽然 size = 1,我相信说“消息太长”是正确的,但为什么是 1?

附:我也试过把:

int rc = mq_receive(gateway, buffer, sizeof(buffer), &prio);

但没有结果。

【问题讨论】:

  • 您是否在某处调用 mq_getattr() 以获得实际大小?否则,您将引用结构所在位置的内存中的任何垃圾。
  • 发布创建队列的代码并尝试从中读取。

标签: queue posix


【解决方案1】:

在调试实时 POSIX 队列时,您应该从一个可以运行的示例程序开始,然后从那里继续。运行示例程序后,确保您自己的代码遵循所有步骤应该很简单。

以下程序已在 Ubuntu 11.04 下测试成功:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <mqueue.h>

#define MQNAME "/pax"
#define MQMESG "Hello there!"

static mqd_t serverUp (void) {
    int rc;
    mqd_t svrHndl;
    struct mq_attr mqAttr;

    printf ("Bringing up server.\n");
    rc = mq_unlink (MQNAME);
    if (rc < 0) {
        printf ("   Warning %d (%s) on server mq_unlink.\n",
            errno, strerror (errno));
    }

    mqAttr.mq_maxmsg = 10;
    mqAttr.mq_msgsize = 1024;
    svrHndl = mq_open (MQNAME, O_RDWR|O_CREAT, S_IWUSR|S_IRUSR, &mqAttr);
    if (svrHndl < 0) {
        printf ("   Error %d (%s) on server mq_open.\n",
            errno, strerror (errno));
        exit (1);
    }
    printf ("   Server opened mqd_t of %d.\n", svrHndl);
    return svrHndl;
}

static void serverReceive (mqd_t svrHndl) {
    int rc;
    char buffer[2048];
    printf ("Server receiving on mqd_t %d.\n", svrHndl);
    rc = mq_receive (svrHndl, buffer, sizeof (buffer), NULL);
    if (rc < 0) {
        printf ("   Error %d (%s) on server mq_receive.\n",
            errno, strerror (errno));
        exit (1);
    }
    printf ("   Received [%s].\n", buffer);
}

static void serverDown (mqd_t svrHndl) {
    printf ("Bringing down server with mqd_t %d.\n", svrHndl);
    mq_close (svrHndl);
}
static void clientSend (void) {
    mqd_t cliHndl;
    int rc;
    printf ("Client sending.\n");
    cliHndl = mq_open (MQNAME, O_RDWR);
    if (cliHndl < 0) {
        printf ("   Error %d (%s) on client mq_open.\n",
            errno, strerror (errno));
        exit (1);
    }
    printf ("   Client opened mqd_t of %d.\n", cliHndl);

    rc = mq_send (cliHndl, MQMESG, sizeof (MQMESG), 1);
    if (rc < 0) {
        printf ("   Error %d (%s) on client mq_send.\n",
            errno, strerror (errno));
        exit (1);
    }

    mq_close (cliHndl);
}

int main (void) {
    mqd_t svrHndl;

    svrHndl = serverUp ();
    clientSend ();
    serverReceive (svrHndl);
    serverDown (svrHndl);

    return 0;
}

我系统上的输出是:

Bringing up server.
   Server opened mqd_t of 3.
Client sending.
   Client opened mqd_t of 4.
Server receiving on mqd_t 3.
   Received [Hello there!].
Bringing down server with mqd_t 3.

【讨论】:

  • +1 表示完整程序和 `rc = mq_unlink (MQNAME);` 在打开之前!操作系统可能还记得旧的mq_msgsize。仅使用新的 mq_msgsize 打开队列是不够的。
【解决方案2】:

您似乎需要更仔细地阅读文档。当您调用mq_receive 时,您应该传递目标缓冲区的大小。 此大小必须大于队列的 mq_msgsize 属性。此外,您似乎在队列属性初始化中存在错误,导致无法正确调用 mq_receive。这是标准消息队列会话:

  1. 填充mq_attr结构(doc):

    struct mq_attr attr;  
    attr.mq_flags = 0;  
    attr.mq_maxmsg = 10;  
    attr.mq_msgsize = 33;  
    attr.mq_curmsgs = 0;  
    
  2. 在主进程 (doc) 中使用 mq_open 创建队列:

    mqd_t queue = mq_open(qname, O_CREAT|O_RDWR, 0644, &attr);
    
  3. 在写入进程中打开写入队列:

    mqd_t queue = mq_open(qname, O_WRONLY);
    

    并发送一些文本。文本长度必须小于队列的mq_msgsize属性(doc):

    mq_send(queue, "some message", strlen("some message")+1, 1);
    
  4. 在阅读器进程中打开阅读队列:

    mqd_t queue = mq_open(qname, O_RDONLY);
    

    然后分配缓冲区并接收消息。缓冲区大小 *必须大于队列的mq_msgsize 属性。这里我们创建 50 字节的缓冲区,而 mq_msgsize == 33 (doc):

    char rcvmsg[50];
    int iret = mq_receive(queue, rcvmsg, 50, NULL);
    

还请记住,您应该使用%ld 打印long 而不是%d

【讨论】:

    【解决方案3】:

    在再次运行程序之前不要忘记取消链接消息队列。如果您不取消链接,它仍将使用旧的消息队列设置。当您使用 Ctrl+C 结束程序时会发生这种情况。我认为将以下代码放在程序的开头是个好主意:

    if(mq_unlink(QUEUENAME) == 0)
      fprintf(stdout, "Message queue %s removed from system.\n", QUEUENAME);
    

    另一种形式(C++ 风格)检查真正的错误(如权限)并忽略队列已经存在或不存在的情况:

    int rc = mq_unlink(name.c_str());
    if (rc != 0 && errno != ENOENT)
          THROW_ERRNO_EXCEPTION();  
    
    // ENOENT is the status code if the queue doesn't exist, which is not an error
    // if you are immediately going to create it.
    

    【讨论】:

      【解决方案4】:

      以上只是一个更正... "此大小必须等于或大于队列的 mq_msgsize 属性"

      如果您传递的是结构而不是缓冲区,则可能需要相等的大小: 见:send struct in mq_send

      【讨论】:

        猜你喜欢
        • 2017-04-20
        • 2017-11-23
        • 2020-07-19
        • 1970-01-01
        • 2013-09-04
        • 1970-01-01
        • 2022-06-15
        • 1970-01-01
        • 2021-03-03
        相关资源
        最近更新 更多