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

MQCB回调触发MQRC_NO_MSG_AVAILABLE时无法识别对应空队列的咨询

解决MQCB回调中MQRC_NO_MSG_AVAILABLE时无法识别对应队列的问题

你这个思路完全没问题——在回调上下文(MQCBD的CallbackContext字段)中存入队列对象句柄,就是处理这种场景的标准且官方推荐的做法。下面给你详细拆解原因、实现步骤和注意事项:

为什么会出现Hobj为MQHO_NONE?

当你用MQGMO_WAIT设置了等待,而队列中没有可用消息触发超时的时候,这个事件本质是连接层面的“无消息通知”,而非某个特定队列的消息事件。所以MQ不会把它关联到具体的队列句柄,此时context->Hobj就会被设为MQHO_NONE(也就是0),这是MQ 8.0版本的预期行为,不是你的代码问题。

具体实现:给每个回调绑定队列句柄

你需要为每个队列单独创建MQCBD结构体,把对应的队列句柄(甚至可以是包含队列名称等更多信息的自定义结构体指针)存入CallbackContext字段,这样即使context->Hobj为空,也能从上下文里拿到对应的队列标识。

修改后的核心代码

// 注册第一个队列的回调时,绑定句柄到上下文
MQCBD cbd1 = {MQCBD_DEFAULT};
cbd1.CallbackType = MQCBT_MESSAGE_CONSUMER;
cbd1.CallbackFunction = &my_message_consumer;
cbd1.CallbackContext = (PMQVOID)&hobj1; // 把队列句柄存入上下文
MQCB(hconn, MQOP_REGISTER, &cbd1, hobj1, &md, &gmo, &c, &r);
check_fail("MQCB register queue 1", c, r);

// 注册第二个队列的回调,同样绑定句柄
MQCBD cbd2 = {MQCBD_DEFAULT};
cbd2.CallbackType = MQCBT_MESSAGE_CONSUMER;
cbd2.CallbackFunction = &my_message_consumer;
cbd2.CallbackContext = (PMQVOID)&hobj2;
MQCB(hconn, MQOP_REGISTER, &cbd2, hobj2, &md, &gmo, &c, &r);
check_fail("MQCB register queue 2", c, r);

更新回调函数获取队列信息

void my_message_consumer(MQHCONN hconn, PMQMD md, PMQGMO gmo, PMQVOID buffer, PMQCBC context) {
    MQHOBJ target_queue = MQHO_NONE;
    // 从回调上下文取出预先存储的队列句柄
    if (context->CallbackContext != NULL) {
        target_queue = *(PMQHOBJ)context->CallbackContext;
    }

    if (context->Reason == MQRC_NO_MSG_AVAILABLE) {
        printf("No message available for queue handle %d\n", target_queue);
    } else {
        printf("Completion code %s, reason %s, object handle %d\n",
               MQCC_STR(context->CompCode), MQRC_STR(context->Reason),
               context->Hobj != MQHO_NONE ? context->Hobj : target_queue);
    }
    events_received++;
}

额外要注意的点

  • 确保CallbackContext指向的内存有效:如果是栈上的变量(比如示例中的hobj1、hobj2),要保证在MQCTL运行期间这些变量不会被销毁;如果是动态分配的结构体,记得在注销回调后释放内存,避免泄漏。
  • 要是你需要更详细的队列信息(比如队列名称),可以自定义一个结构体:
    typedef struct {
        MQHOBJ hobj;
        char queue_name[MQ_Q_NAME_LENGTH + 1];
    } QueueCallbackContext;
    
    然后把这个结构体的指针存入CallbackContext,回调时就能直接拿到队列名称了。
  • 你的MQ版本(8.0.0.2队列管理器 + 8.0.0.5客户端)完全支持这个特性,没有遗漏任何关键配置——这就是MQ处理等待超时事件的标准方式。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:41:40