我正在使用队列实现两个进程之间的通信。问题是,当我调用函数mq_receive时,我收到此错误:消息太长。
我做了以下事情:
struct mq_attr attr;
long size = attr.mq_msgsize;
.... // initializing the queue "/gateway"
int rc = mq_receive(gateway, buffer, size, &prio);
如果我打印尺寸值,我得到尺寸= 1,而当我打印相同尺寸但从另一个程序(通过相同机制获得)时,我得到的东西不是长整数(-1217186280)...
我怎样才能解决这个错误?....所以当size = 1时,我认为说“消息太长”是正确的,但为什么是1?
P.S。我也尝试过:
int rc = mq_receive(gateway, buffer, sizeof(buffer), &prio);
但没有结果。
答案 0 :(得分:19)
您似乎需要更仔细地阅读文档。当您调用mq_receive
时,您应该传递目标缓冲区的大小。 此大小必须大于队列的mq_msgsize属性。此外,您似乎在队列属性初始化中出现错误,导致无法进行正确的mq_receive
调用。这是标准的消息队列会话:
填写mq_attr
struct(doc):
struct mq_attr attr;
attr.mq_flags = 0;
attr.mq_maxmsg = 10;
attr.mq_msgsize = 33;
attr.mq_curmsgs = 0;
在主进程(doc)中使用mq_open
创建队列:
mqd_t queue = mq_open(qname, O_CREAT|O_RDWR, 0644, &attr);
在编写进程中打开队列进行编写:
mqd_t queue = mq_open(qname, O_WRONLY);
并发送一些文字。文本的长度必须小于队列的mq_msgsize
属性(doc):
mq_send(queue, "some message", strlen("some message")+1, 1);
在读者进程中打开队列进行阅读:
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
。
答案 1 :(得分:7)
在调试实时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.
答案 2 :(得分:5)
在再次运行程序之前,请不要忘记取消链接消息队列。如果您不取消链接,它仍将使用旧的邮件队列设置。使用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.
答案 3 :(得分:0)
只是上面的一个更正... “此大小必须等于或大于队列的mq_msgsize属性”
如果要传递结构而不是缓冲区,则可能需要相等大小: 参见:send struct in mq_send