Safe API — 永不抛异常变体
概述
UI 主线程 / 批处理不希望被一条 RPC 失败抛出的 OpcUaException 中断, SDK 为常用调用各提供一个 Safe 版本 — 任何异常折叠为 StatusCode, 调用方用 std::pair / 结构体判读。
对应规范段: Browse Part 4 §5.8, Read §5.10.2, Write §5.10.4, Call §5.11.2, HistoryRead Part 11 §6.5。
API
| 方法 | 类别 | 读写 | 说明 |
|---|---|---|---|
| ua.BrowseSafe(nodeId, filter) | 浏览 | 读 | 返回 BrowseResult { status, references } |
| ua.ReadSafe(nodeId, attribute) | 读 | 读 | 返回 ReadResult { status, value } |
| ua.WriteSafe(nodeId, value, attribute) | 写 | 写 | 返回 StatusCode |
| ua.CallSafe(objectId, methodId, inputs) | 方法 | 写 | 返回 CallResult { status, outputs } |
| ua.ReadHistorySafe(nodeId, t0, t1, max) | 历史 | 读 | 返回 HistoryResult { status, values } |
代码示例
#include <darra/opcua.h>
using namespace darra::opcua;
DarraOpcUa ua("opc.tcp://localhost:4840");
ua.Connect();
// 1) 浏览 - 节点删除不让全树报错
auto br = ua.BrowseSafe("ns=2;s=Boiler1");
if (br.status != StatusCode::Good) {
std::cout << "Browse 失败 " << br.status << "\n";
} else {
for (auto& r : br.references) std::cout << r.browse_name << "\n";
}
// 2) 批量轮询 - 单点失败不打断
for (auto& nid : node_list) {
auto rr = ua.ReadSafe(nid);
if (rr.status == StatusCode::Good && rr.value) {
std::cout << nid << " = " << rr.value->value << "\n";
} else {
std::cout << nid << " = <" << rr.status << ">\n";
}
}
// 3) 批量下发参数
for (auto& [nid, val] : setpoints) {
auto rc = ua.WriteSafe(nid, Variant(val));
if (rc != StatusCode::Good) std::cout << "写 " << nid << " 失败 " << rc << "\n";
}
// 4) 调用方法
auto cr = ua.CallSafe("ns=2;s=Robot", "ns=2;s=Robot.Home", {});
if (cr.status != StatusCode::Good) std::cerr << "Home 失败: " << cr.status << "\n";
// 5) 历史
auto hr = ua.ReadHistorySafe("ns=2;s=Temp", t0, t1, 5000);
与重试机制的关系
普通 Read/Write/Browse/Call/ReadHistory 内部都包了 RetryOnSessionFault, session 级故障会自动重连一次。Safe 变体也受益于自动重连, 把"重连后仍失败"的异常折叠为 StatusCode。
最佳实践
- UI 主线程一律用 Safe — C++ 异常逃逸到 Qt event loop 会让进程挂掉
- 批处理 / 巡检循环用 Safe
- 业务关键路径仍用普通版本
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| BrowseSafe | browse_safe | browseSafe | BrowseSafe | browse_safe | DarraUa_Session_BrowseSafe |
| ReadSafe | read_safe | readSafe | ReadSafe | read_safe | DarraUa_Session_ReadSafe |
| WriteSafe | write_safe | writeSafe | WriteSafe | write_safe | DarraUa_Session_WriteSafe |
| CallSafe | call_safe | callSafe | CallSafe | call_safe | DarraUa_Session_CallSafe |
| ReadHistorySafe | read_history_safe | readHistorySafe | ReadHistorySafe | read_history_safe | DarraUa_Session_ReadHistorySafe |