node-opcua客户端批量监控多OPC UA节点失效问题问询
node-opcua批量监控节点异常:仅部分节点被成功监控
当前行为
使用forEach循环批量监控OPC UA节点时,待监控数组包含5个节点,但不同版本的node-opcua存在监控节点不全的问题:
- node-opcua 2.30.0:仅能监控2个节点
- node-opcua 2.72.2:仅能监控1个节点
对比UA Expert工具,所有5个节点均可正常被监控。
预期行为
所有待监控的OPC UA节点均能被正常监控,并在数据变化时接收通知。
复现代码
const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"] const monitoringParamaters = { samplingInterval: 100, discardOldest: true, queueSize: 10, }; idsToMonitor.forEach((nodeId) => { opc_subscription.monitor({ nodeId: resolveNodeId(nodeId), attributeId: AttributeIds.Value, }, monitoringParamaters, TimestampsToReturn.Both, (err, monitoredItem) => { monitoredItem.on("changed", function (dataValue) { var Node = {nodeId: nodeId, nodeName: "111" , nodeValue: dataValue.value.value , nodeTimestamp: dataValue.sourceTimestamp.toISOString()}; console.log(JSON.stringify(Node)); }); }); });
环境信息
- node-opcua角色:OPC UA客户端
- 安装方式:npm包安装
- 操作系统:Windows 10
- Node.js版本:16.16.0
问题原因
forEach循环会同步触发所有opc_subscription.monitor异步调用,短时间内大量并发请求可能被OPC UA服务器限流,或node-opcua客户端内部因请求积压导致部分监控项创建失败。
修复方案
推荐使用批量创建监控项的API,这是node-opcua官方支持的规范操作方式,效率更高且能避免并发问题:
const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"]; const monitoringParameters = { samplingInterval: 100, discardOldest: true, queueSize: 10, }; // 构造批量监控项参数 const itemsToMonitor = idsToMonitor.map(nodeId => ({ nodeId: resolveNodeId(nodeId), attributeId: AttributeIds.Value, })); // 调用批量创建API opc_subscription.createMonitoredItems( TimestampsToReturn.Both, itemsToMonitor.map(item => ({ itemToMonitor: item, monitoringParameters: monitoringParameters })), (err, results) => { if (err) { console.error("批量创建监控项失败:", err); return; } results.forEach((result, index) => { const targetNodeId = idsToMonitor[index]; if (result.statusCode !== StatusCodes.Good) { console.error(`节点${targetNodeId}监控创建失败:${result.statusCode}`); return; } const monitoredItem = result.monitoredItem; monitoredItem.on("changed", (dataValue) => { const nodeData = { nodeId: targetNodeId, nodeName: "111", nodeValue: dataValue.value.value, nodeTimestamp: dataValue.sourceTimestamp.toISOString() }; console.log(JSON.stringify(nodeData)); }); }); } );
如果需要严格串行创建监控项(适用于特殊场景),可使用异步循环:
const idsToMonitor = ["ns=4;i=16", "ns=4;i=17", "ns=4;i=11", "ns=4;i=12", "ns=4;i=18"]; const monitoringParameters = { samplingInterval: 100, discardOldest: true, queueSize: 10, }; async function createMonitoredItemsSequentially() { for (const nodeId of idsToMonitor) { await new Promise((resolve, reject) => { opc_subscription.monitor({ nodeId: resolveNodeId(nodeId), attributeId: AttributeIds.Value, }, monitoringParameters, TimestampsToReturn.Both, (err, monitoredItem) => { if (err) { console.error(`节点${nodeId}监控创建失败:`, err); reject(err); return; } monitoredItem.on("changed", (dataValue) => { const nodeData = { nodeId: nodeId, nodeName: "111", nodeValue: dataValue.value.value, nodeTimestamp: dataValue.sourceTimestamp.toISOString() }; console.log(JSON.stringify(nodeData)); }); resolve(); }); }); } } // 执行串行创建 createMonitoredItemsSequentially().catch(err => console.error("串行创建监控项失败:", err));
说明
createMonitoredItems会将所有监控请求合并为一个批量请求发送给服务器,符合OPC UA协议规范,能有效避免并发请求导致的限流问题。- 串行方式虽然可靠,但效率低于批量创建,仅建议在特定场景下使用。
内容的提问来源于stack exchange,提问作者Abdelhak Sidi Ali Mebarek
相关产品推荐
相关产品推荐

