跳到主要内容

Browse (C)

DarraUa_Session_BrowseNode(h, node_id, filter, &res) — 列出指定节点的直接子节点 (一层).

前置阅读 / 配套

API

OPCUA_API DarraUa_Status OPCUA_CALL DarraUa_Session_BrowseNode(
DarraUa_SessionHandle h,
const char* node_id_str,
DarraUa_NodeClass filter_node_class,
DarraUa_BrowseResult** out_result);

OPCUA_API uint32_t OPCUA_CALL
DarraUa_BrowseResult_GetCount(const DarraUa_BrowseResult* r);

OPCUA_API const DarraUa_ReferenceDescription* OPCUA_CALL
DarraUa_BrowseResult_GetReference(const DarraUa_BrowseResult* r, uint32_t index);

OPCUA_API void OPCUA_CALL
DarraUa_BrowseResult_Delete(DarraUa_BrowseResult* r);

out_result 由 Stack 分配, 用 _Delete 释放. 失败时 *out_result = NULL.

ReferenceDescription 字段访问器

OPCUA_API const char* OPCUA_CALL
DarraUa_Ref_GetBrowseName(const DarraUa_ReferenceDescription* rd);

OPCUA_API const char* OPCUA_CALL
DarraUa_Ref_GetDisplayName(const DarraUa_ReferenceDescription* rd);

OPCUA_API int32_t OPCUA_CALL
DarraUa_Ref_GetNodeClass(const DarraUa_ReferenceDescription* rd);

OPCUA_API int32_t OPCUA_CALL
DarraUa_Ref_GetNodeIdString(
const DarraUa_ReferenceDescription* rd,
char* buf, int32_t buf_size);

Get* 返回的 const char* 生命周期 = BrowseResult, 不要 free.

用法

DarraUa_BrowseResult* br = NULL;
DarraUa_Status st = DarraUa_Session_BrowseNode(
h, "ns=2;s=Boiler1",
UA_NODE_CLASS_UNSPECIFIED,
&br);
if (!UA_STATUS_IS_GOOD(st) || !br) {
fprintf(stderr, "Browse failed: %s\n", DarraUa_StatusName(st));
return;
}

uint32_t n = DarraUa_BrowseResult_GetCount(br);
char id_buf[128];
for (uint32_t i = 0; i < n; ++i) {
const DarraUa_ReferenceDescription* rd =
DarraUa_BrowseResult_GetReference(br, i);
if (!rd) continue;
int32_t nc = DarraUa_Ref_GetNodeClass(rd);
const char* name = DarraUa_Ref_GetBrowseName(rd);
const char* dname = DarraUa_Ref_GetDisplayName(rd);
DarraUa_Ref_GetNodeIdString(rd, id_buf, (int32_t)sizeof(id_buf));
printf(" [class=%d] %-20s %s -> %s\n",
nc, name ? name : "", dname ? dname : "", id_buf);
}

DarraUa_BrowseResult_Delete(br);

批量浏览 (BrowseNodes)

如果同时要浏览多个节点 (例如 GUI 初次展开树), 用 BrowseNodes 一次 RPC:

OPCUA_API DarraUa_Status OPCUA_CALL DarraUa_Session_BrowseNodes(
DarraUa_SessionHandle h,
const char* const* node_id_strs,
uint32_t count,
DarraUa_NodeClass filter_node_class,
DarraUa_BrowseResult** out_results); /* 调用方分配 count 个槽 */
const char* roots[] = { "i=85" /* Objects */, "i=86" /* Types */ };
DarraUa_BrowseResult* results[2] = { NULL };
DarraUa_Session_BrowseNodes(h, roots, 2,
UA_NODE_CLASS_UNSPECIFIED, results);

for (uint32_t r = 0; r < 2; ++r) {
if (!results[r]) {
printf("%s: failed\n", roots[r]);
continue;
}
uint32_t cnt = DarraUa_BrowseResult_GetCount(results[r]);
printf("%s: %u children\n", roots[r], cnt);
DarraUa_BrowseResult_Delete(results[r]);
}

如果某个节点浏览失败, 对应槽位 results[i] = NULL, 不影响其他.

NodeClass filter

typedef enum {
UA_NODE_CLASS_UNSPECIFIED = 0,
UA_NODE_CLASS_OBJECT = 1,
UA_NODE_CLASS_VARIABLE = 2,
UA_NODE_CLASS_METHOD = 4,
UA_NODE_CLASS_OBJECT_TYPE = 8,
UA_NODE_CLASS_VARIABLE_TYPE = 16,
UA_NODE_CLASS_REFERENCE_TYPE= 32,
UA_NODE_CLASS_DATA_TYPE = 64,
UA_NODE_CLASS_VIEW = 128
} DarraUa_NodeClass;

按位或可组合 (例如 OBJECT | VARIABLE).

/* 只看 Variable */
DarraUa_Session_BrowseNode(h, "ns=2;s=Boiler1",
UA_NODE_CLASS_VARIABLE, &br);

/* 只看 Method */
DarraUa_Session_BrowseNode(h, "ns=2;s=Calculator",
UA_NODE_CLASS_METHOD, &br);

大节点的分页 (ContinuationPoint)

如果一个节点有 1000+ 个子节点, 单次 Browse 服务端可能截断. 此时 BrowseNode 返回的 BrowseResult 内含 ContinuationPoint, 用 _GetContinuationPoint 拿到后调 BrowseNext:

const uint8_t* cp = NULL;
int32_t cp_len = 0;
cp = DarraUa_BrowseResult_GetContinuationPoint(br, &cp_len);
if (cp && cp_len > 0) {
DarraUa_BrowseResult* next = NULL;
DarraUa_Session_BrowseNext(h, /*release*/ 0, cp, cp_len, &next);
/* ... 处理 next ... */
DarraUa_BrowseResult_Delete(next);
}

完整循环模板见 Browse 自动分页.

错误码

状态码含义
Good成功
BadNodeIdUnknownNodeId 不存在
BadNodeIdInvalidNodeId 字符串解析失败
BadCommunicationError网络故障

性能

  • 单次 Browse: ~5-15 ms
  • BrowseNodes 批量: 总耗时 ~ 单次 (省 N-1 次往返)
  • 1000+ 子节点会分页, 加 BrowseNext 处理

DarraUa_Session_BrowseFiltered — 方向 + 引用类型过滤

DarraUa_StatusCode DarraUa_Session_BrowseFiltered(
DarraUa_SessionHandle h,
const char* nid,
DarraUa_NodeClass node_class_filter,
DarraUa_BrowseDirection direction, // FORWARD / INVERSE / BOTH
const char* reference_type_id, // NULL 表所有引用
int include_subtypes, // 0/1
uint32_t result_mask, // 0x3F 全字段
DarraUa_Reference** out_refs,
size_t* out_count);

相关结构:

typedef enum {
BD_FORWARD = 0, // 仅正向, 父→子
BD_INVERSE = 1, // 仅反向, 子→父
BD_BOTH = 2 // 正反向都返回
} DarraUa_BrowseDirection;

示例

// 1) 正向 + 仅 HierarchicalReferences (i=33)
DarraUa_Reference* refs = NULL;
size_t n = 0;
DarraUa_Session_BrowseFiltered(ua, "ns=2;s=Boiler1",
NODE_CLASS_UNSPECIFIED, BD_FORWARD,
"i=33", 1, 0x3F, &refs, &n);
for (size_t i = 0; i < n; ++i) printf("%s\n", refs[i].browse_name);
DarraUa_FreeReferences(refs, n);

// 2) 反向找父
DarraUa_Reference* parents = NULL;
size_t pn = 0;
DarraUa_Session_BrowseFiltered(ua, "ns=2;s=Tank.Level",
NODE_CLASS_UNSPECIFIED, BD_INVERSE,
NULL, 1, 0x3F, &parents, &pn);
DarraUa_FreeReferences(parents, pn);

实现说明

  • Stack 提供 DarraUa_Session_BrowseWithFilter 时直调原生
  • 否则 fallback 到 Browse + 客户端按 NodeClass 过滤; reference_type_id / direction 在 fallback 模式下无法精确生效, 通过事件回调推 Warning

下一步