You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

open62541中使用UA_Client_MonitoredItems_createDataChanges批量创建监控项后回调不触发问题求助

open62541中使用UA_Client_MonitoredItems_createDataChanges批量创建监控项后回调不触发问题求助

各位open62541的大佬们,我最近在用open62541 v1.x开发OPC UA客户端时,遇到了批量创建监控项的回调不触发的诡异问题——单条创建标签一切正常,换成批量API后,监控项明明创建成功了,但回调函数死活不执行,实在卡壳了,来求助大家!

背景

我需要批量订阅大量OPC UA标签,单条调用UA_Client_MonitoredItems_createDataChange()完全没问题,但为了性能考虑换成批量API后就出问题了。

✅ 正常工作的单条创建实现

先贴一下单条创建的核心代码,这部分是完全正常的:

UA_MonitoredItemCreateResult monResponse = UA_Client_MonitoredItems_createDataChange(
    client, subscriptionId, UA_TIMESTAMPSTORETURN_BOTH,
    monRequest, monContext, handler_DataChange, nullptr);

对应的现象:

  • 所有监控项都能成功创建
  • 回调函数handler_DataChange被正确调用
  • 标签值能正常接收

❌ 不工作的批量创建实现

换成批量APIUA_Client_MonitoredItems_createDataChanges()后,监控项创建成功,但回调完全不触发。以下是核心实现代码:

UA_CreateMonitoredItemsRequest req;
UA_CreateMonitoredItemsRequest_init(&req);
req.subscriptionId = subscriptionId;
req.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
req.itemsToCreateSize = tags.size();
req.itemsToCreate = (UA_MonitoredItemCreateRequest*)UA_Array_new(
    tags.size(), &UA_TYPES[UA_TYPES_MONITOREDITEMCREATEREQUEST]);

// 用全局容器持久化存储上下文和回调,避免超出作用域被销毁
auto& ctxList = subscriptionContexts[subscriptionId];
auto& cbList = subscriptionCallbacks[subscriptionId];

for (size_t i = 0; i < tags.size(); i++) {
    UA_MonitoredItemCreateRequest_init(&req.itemsToCreate[i]);
    UA_NodeId nodeId = parseNodeIdFromAddress(tags[i]->address, logger);
    UA_NodeId_copy(&nodeId, &req.itemsToCreate[i].itemToMonitor.nodeId);
    req.itemsToCreate[i].itemToMonitor.attributeId = UA_ATTRIBUTEID_VALUE;

    // 存储上下文到持久化列表
    auto ctx = std::make_unique<MonContext>();
    ctx->deviceId = device->uniqueId;
    ctx->tag = tags[i];
    ctxList.push_back(std::move(ctx));

    // 存储回调函数到持久化列表
    cbList.push_back(handler_DataChange);

    UA_NodeId_clear(&nodeId);
}

// 转换为批量API需要的原始指针数组
std::vector<void*> ctxRaw;
for (auto& c : ctxList) ctxRaw.push_back(c.get());
std::vector<UA_Client_DataChangeNotificationCallback> cbRaw;
for (auto& cb : cbList) cbRaw.push_back(cb);

// 调用批量创建API
UA_CreateMonitoredItemsResponse resp = UA_Client_MonitoredItems_createDataChanges(
    client, req, ctxRaw.data(), cbRaw.data(), nullptr);

对应的现象:

  • ✅ 服务器返回UA_STATUSCODE_GOOD,所有监控项创建成功
  • ✅ 每个项都拿到了正确的MonitoredItemId
  • ❌ 所有分配的回调函数handler_DataChange从未被触发
  • ❌ 客户端能收到服务器的Publish响应,但响应里的通知数量为0

我已经排查过的点

  1. 回调和上下文的生命周期:用全局容器持久化存储了ctxListcbList,绝对没有超出作用域被销毁
  2. 回调函数本身:同一个handler_DataChange在单条模式下完全正常工作
  3. 服务器状态:服务器能正常发布标签值(单条订阅可以收到)
  4. 订阅参数:采样间隔、队列大小等参数和单条模式完全一致,都是正确的
  5. 返回结果校验:创建请求的响应里,所有项的状态码都是UA_STATUSCODE_GOOD

我的疑问

为什么批量API能成功创建监控项,但完全不触发回调?单条模式下同一个回调明明是正常的。

关于批量API的上下文和回调数组,有没有什么特殊的结构要求?比如存储顺序、格式?或者open62541 v1.x在批量创建监控项上有已知的限制或bug吗?

折腾了好几天都没找到问题所在,求各位大佬指点迷津!🙏

火山引擎 最新活动