【发布时间】:2018-05-12 06:46:29
【问题描述】:
我正在使用MQCB 函数为我正在读取的队列添加消息消费者回调函数。我正在尝试从同一连接上的两个队列中读取数据,并且在接收消息时似乎工作正常:我的回调函数获取接收消息的队列的对象句柄。
但是,当我收到一个MQRC_NO_MSG_AVAILABLE 事件时(因为我在我的消费者上设置了MQGMO_WAIT),对象句柄是MQHO_NONE,所以我不知道该事件指的是哪个队列。我可以通过将对象句柄放在回调上下文中来解决这个问题,但它应该这样做吗?还是我在这里遗漏了一些明显的东西?
我正在使用 C 客户端库版本 8.0.0.5 连接到在 Linux 上运行版本 8.0.0.2 的队列管理器,同样在 Linux 上。这是我的示例程序的输出,显示对象句柄为 0:
Opened queue 'AMQ.5A55ED982D616602 ' with handle 101
Opened queue 'AMQ.5A55ED982D616603 ' with handle 102
Completion code MQCC_FAILED, reason MQRC_NO_MSG_AVAILABLE, object handle 0
Completion code MQCC_FAILED, reason MQRC_NO_MSG_AVAILABLE, object handle 0
还有程序本身:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <cmqc.h>
#include <cmqxc.h>
#include <cmqstrc.h>
void my_message_consumer(MQHCONN, PMQMD, PMQGMO, PMQVOID, PMQCBC);
volatile unsigned events_received = 0;
void
check_fail(const char *action, MQLONG comp_code, MQLONG reason)
{
if (comp_code != MQCC_OK) {
fprintf(stderr, "%s failed with %s %s\n",
action, MQCC_STR(comp_code), MQRC_STR(reason));
exit(1);
}
}
int
main()
{
MQHCONN hconn;
MQHOBJ hobj1, hobj2;
MQOD od = {MQOD_DEFAULT};
char queue_name[MQ_Q_NAME_LENGTH + 1];
MQLONG c, r;
MQCONN("", &hconn, &c, &r);
check_fail("MQCONN", c, r);
/* Open two dynamic queues */
strcpy(od.ObjectName, "SYSTEM.DEFAULT.MODEL.QUEUE");
MQOPEN(hconn, &od, MQOO_INPUT_EXCLUSIVE, &hobj1, &c, &r);
check_fail("MQOPEN", c, r);
strncpy(queue_name, od.ObjectName, MQ_Q_NAME_LENGTH);
queue_name[MQ_Q_NAME_LENGTH] = '\0';
printf("Opened queue '%48s' with handle %d\n", queue_name, hobj1);
strcpy(od.ObjectName, "SYSTEM.DEFAULT.MODEL.QUEUE");
MQOPEN(hconn, &od, MQOO_INPUT_EXCLUSIVE, &hobj2, &c, &r);
check_fail("MQOPEN", c, r);
strncpy(queue_name, od.ObjectName, MQ_Q_NAME_LENGTH);
queue_name[MQ_Q_NAME_LENGTH] = '\0';
printf("Opened queue '%48s' with handle %d\n", queue_name, hobj2);
/* Add a callback with zero WaitInterval for both queues */
MQMD md = {MQMD_DEFAULT};
MQGMO gmo = {MQGMO_DEFAULT};
MQCBD cbd = {MQCBD_DEFAULT};
gmo.Options = MQGMO_NO_SYNCPOINT | MQGMO_WAIT;
gmo.WaitInterval = 0;
cbd.CallbackType = MQCBT_MESSAGE_CONSUMER;
cbd.CallbackFunction = &my_message_consumer;
MQCB(hconn, MQOP_REGISTER, &cbd, hobj1, &md, &gmo, &c, &r);
check_fail("MQCB", c, r);
MQCB(hconn, MQOP_REGISTER, &cbd, hobj2, &md, &gmo, &c, &r);
check_fail("MQCB", c, r);
/* Start consuming */
MQCTLO ctlo = {MQCTLO_DEFAULT};
MQCTL(hconn, MQOP_START, &ctlo, &c, &r);
check_fail("MQCTL start", c, r);
/* Wait until events received */
while (events_received < 2)
sleep(1);
return 0;
}
void
my_message_consumer(MQHCONN hconn, PMQMD md, PMQGMO gmo,
PMQVOID buffer, PMQCBC context)
{
printf("Completion code %s, reason %s, object handle %d\n",
MQCC_STR(context->CompCode), MQRC_STR(context->Reason),
context->Hobj);
events_received++;
}
编译:
gcc -o mq-no-msg mq-no-msg.c -g -Wall -I/opt/mqm/inc -L/opt/mqm/lib64 -lmqic_r -Wl,-rpath=/opt/mqm/lib64
并在运行前设置MQSERVER 环境变量。
【问题讨论】:
-
是的,这让我很困惑。我将
CallbackType指定为“消息使用者”而不是“事件处理程序”,并且该页面显示“为影响整个消息使用者环境的条件调用事件处理程序”(而不是单个队列为空) - 那为什么在这种情况下,我的消息使用者是否充当事件处理程序?... -
是的,我想我真的不需要“无消息”事件 - 如果我需要它,答案似乎是接受它的工作方式,并且将我需要的内容存储在 CallbackArea 中。谢谢!
-
将我的 cmets 卷入答案中。
-
我用更多细节更新了我的答案,并添加了一个用例,您可能希望在您的消费者中接收
MQRC_NO_MSG_AVAILABLE事件消息,但您发现默认情况下,如果您注册了多个消费者,使用CallbackArea可能是解决此问题的一种方法。 -
如果您有权打开 PMR,可能值得向 IBM 澄清。 KC 关于
Hobj值、For an event handler, this value is MQHO_NONE的状态,并且正如您正确指出的那样,您没有注册事件处理程序。我也没有在 KC 中找到将事件消息发送给消费者的任何直接引用,但是我引用的发送给消费者的状态事件的 IBM 演示只是那些与它正在消费的队列相关的事件。在我看来,MQCBC应该包含关联的Hobj而不是MQHO_NONE,这似乎是合理的。
标签: ibm-mq