BrowseCrawler
概述
BFS 队列遍历整棵 AddressSpace 子树, 双重保护 (max_depth + max_nodes)。
API
| 函数 | 类别 | 读写 | 说明 |
|---|---|---|---|
| DarraUa_BrowseCrawler_New(ua, max_depth, max_nodes, filter, &out_h) | 构造 | — | 构造 |
| DarraUa_BrowseCrawler_Free(h) | 释放 | — | 析构 |
| DarraUa_BrowseCrawler_Crawl(h, root, progress_cb, cancel_flag, &out_result) | 方法 | 读 | 同步 BFS, 阻塞调用 |
| DarraUa_FreeCrawlResult(result) | 释放 | — | 释放结果 |
DarraUa_CrawlResult
typedef struct {
DarraUa_CrawlNode* nodes; // 扁平节点数组
size_t node_count;
DarraUa_KvPair* children; // 父→子列表 (序列化为 KV)
size_t children_count;
int64_t elapsed_ms;
} DarraUa_CrawlResult;
代码示例
#include <opcua.h>
#include <stdatomic.h>
void on_progress(int count, const char* nid, void* ctx) {
printf("\r已抓 %d 个, 当前 %s", count, nid);
}
int main() {
DarraUa_Session* ua;
DarraUa_Session_New("opc.tcp://localhost:4840", &ua);
DarraUa_Session_Connect(ua);
// 1) 爬整棵 ObjectsFolder
DarraUa_BrowseCrawler* crawler;
DarraUa_BrowseCrawler_New(ua, 8, 50000, NODE_CLASS_UNSPECIFIED, &crawler);
atomic_int cancel_flag = 0;
DarraUa_CrawlResult* result = NULL;
DarraUa_BrowseCrawler_Crawl(crawler, "i=85", on_progress, &cancel_flag, NULL, &result);
printf("\n共 %zu 节点, 耗时 %lld ms\n",
result->node_count, (long long)result->elapsed_ms);
for (size_t i = 0; i < result->node_count; ++i)
printf(" %s (%s)\n", result->nodes[i].browse_name, result->nodes[i].node_id);
DarraUa_FreeCrawlResult(result);
DarraUa_BrowseCrawler_Free(crawler);
DarraUa_Session_Free(ua);
return 0;
}
性能
| 节点规模 | 耗时 |
|---|---|
| 1,000 | ~0.5s |
| 10,000 | ~5s |
| 50,000 | ~25s |
最佳实践
- 限定 root, 不要从 i=84 (Root) 开始
- 用 nodeClassFilter 节省内存
- 启动时一次性爬
- 给用户取消按钮 (cancel_flag)
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| BrowseCrawler | BrowseCrawler | BrowseCrawler | BrowseCrawler | BrowseCrawler | DarraUa_BrowseCrawler_* |
| CrawlAsync | crawl_async | crawlAsync | CrawlAsync | crawl_async | DarraUa_BrowseCrawler_Crawl |