RegisterNodes / UnregisterNodes (C)
RegisterNodes 服务把客户端常用的 NodeId 注册到服务端, 服务端返回临时高效 NodeId (生命周期 = Session). 后续 Read / Write / MonitoredItem 用这个临时 ID 比原始 NodeId 快得多 (服务端跳过完整 NodeId 解析).
适用判断
- 单次脚本 → 不需要
- 长期运行高频访问相同节点 → 强烈推荐
- 大规模 SCADA 1000+ Tag 持续监控 → 必须
API
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_RegisterNodes(
DarraUa_SessionHandle h,
const char* const* node_ids_to_register,
uint32_t count,
char*** out_registered_node_ids);
DARRA_OPCUA_API DarraUa_Status DARRA_OPCUA_CALL DarraUa_Session_UnregisterNodes(
DarraUa_SessionHandle h,
const char* const* registered_node_ids,
uint32_t count);
out_registered_node_ids 指向一个 char** 数组, 每项是服务端给的临时 NodeId 字符串. 用 DarraUa_Free 逐个释放, 再 DarraUa_Free 数组本身.
完整用法
#include <darra_opcua/darra_opcua.h>
#include <stdio.h>
int main(void)
{
/* ... 假设已 Connect ... */
DarraUa_SessionHandle h = /* ... */;
/* 1. 应用启动时注册 */
const char* orig[] = {
"ns=2;s=Plant.Line1.Sensor.Temperature",
"ns=2;s=Plant.Line1.Sensor.Pressure",
"ns=2;s=Plant.Line1.Sensor.FlowRate",
};
uint32_t count = 3;
char** registered = NULL;
DarraUa_Status st = DarraUa_Session_RegisterNodes(h, orig, count, ®istered);
if (!DARRA_UA_STATUS_IS_GOOD(st) || !registered) {
fprintf(stderr, "RegisterNodes failed: %s\n", DarraUa_StatusName(st));
return -1;
}
for (uint32_t i = 0; i < count; ++i)
printf("%s -> %s\n", orig[i], registered[i] ? registered[i] : "(null)");
/* 2. 后续高频访问用临时 ID (快得多) */
for (int j = 0; j < 10000; ++j) {
DarraUa_Status rs = 0;
DarraUa_DataValue* dv = DarraUa_Session_ReadNode(
h, registered[0], DARRA_UA_ATTR_VALUE, &rs);
if (dv) DarraUa_DataValue_Delete(dv);
}
/* 3. 应用退出前释放 — 先 Unregister 服务端句柄 */
DarraUa_Session_UnregisterNodes(
h, (const char* const*)registered, count);
/* 4. 释放本地字符串数组 */
for (uint32_t i = 0; i < count; ++i)
if (registered[i]) DarraUa_Free(registered[i]);
DarraUa_Free(registered);
return 0;
}
何时用
| 场景 | 必要性 |
|---|---|
| 单次脚本, 100 个节点 | 低 (省的开销可忽略) |
| 长期运行, 高频访问相同节点 | 高 (省时显著) |
| 大规模 SCADA, 1000+ Tag 持续监控 | 必须 |
性能数据
服务端 NodeId 解析的耗时取决于实现:
- 数字 NodeId (
i=2258) 通常 O(1) 哈希查找 — RegisterNodes 收益小 - 字符串 NodeId 长路径 (
ns=2;s=Plant.Line1.Sensor.Temperature) — 服务端可能 O(n) 字符串解析, RegisterNodes 收益大 (典型 30-50% 加速)
注意
- 注册的临时 ID 只在当前 Session 有效, Disconnect 后失效
- Session 重连后 (TransferSubscriptions) 临时 ID 通常仍有效, 但保险起见重新 Register
- 不释放的临时 ID 会随 Session 关闭自动 GC, 但显式 Unregister 是好习惯
- 临时 ID 字符串内存由 Stack malloc, 必须用
DarraUa_Free释放, 不要用标准free