跳到主要内容

Safe API — 永不抛异常变体

概述

UI 主线程 / 批处理不希望被一条 RPC 失败抛出的 OpcUaException 中断, SDK 为常用调用各提供一个 Safe 版本 — 任何异常折叠为 StatusCode, 调用方用 Result 包装类判读。

对应规范段: 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 }, 失败时 value=null
ua.writeSafe(nodeId, value, attribute)返回 StatusCode
ua.callSafe(objectId, methodId, inputs)方法返回 CallResult { status, outputs }
ua.readHistorySafe(nodeId, t0, t1, max)历史返回 HistoryResult { status, values }

代码示例

import com.darra.opcua.*;

try (DarraOpcUa ua = new DarraOpcUa("opc.tcp://localhost:4840")) {
ua.connect();

// 1) 浏览 - 节点删除不让全树报错
BrowseResult br = ua.browseSafe("ns=2;s=Boiler1", NodeClass.Unspecified);
if (br.status != StatusCode.Good) {
System.out.println("Browse 失败 " + br.status);
} else {
for (OpcUaReference r : br.references)
System.out.println(r.browseName);
}

// 2) 批量轮询 - 单点失败不打断
for (String nid : nodeList) {
ReadResult rr = ua.readSafe(nid, AttributeId.Value);
if (rr.status == StatusCode.Good && rr.value != null) {
try (DataValue dv = rr.value) {
System.out.println(nid + " = " + dv.value);
}
} else {
System.out.println(nid + " = <" + rr.status + ">");
}
}

// 3) 批量下发参数
for (Map.Entry<String, Object> sp : setpoints.entrySet()) {
StatusCode rc = ua.writeSafe(sp.getKey(), new Variant(sp.getValue()));
if (rc != StatusCode.Good)
System.out.println("写 " + sp.getKey() + " 失败 " + rc);
}

// 4) 调用方法
CallResult cr = ua.callSafe("ns=2;s=Robot", "ns=2;s=Robot.Home");
if (cr.status != StatusCode.Good)
JOptionPane.showMessageDialog(null, "Home 失败: " + cr.status);

// 5) 历史读
HistoryResult hr = ua.readHistorySafe("ns=2;s=Temp", t0, t1, 5000);
}

与重试机制的关系

普通 read/write/browse/call/readHistory 内部都包了 retryOnSessionFault, session 级故障会自动重连一次。Safe 变体也受益于自动重连, 把"重连后仍失败"的异常折叠为 StatusCode。

最佳实践

  • UI 主线程 (Swing/JavaFX) 一律用 Safe — 异常逃逸进 EDT 会让 UI 卡死
  • 批处理 / 巡检循环用 Safe
  • 业务关键路径仍用普通版本

跨语言对照

C#PythonJavaC++RustC
BrowseSafebrowse_safebrowseSafeBrowseSafebrowse_safeDarraUa_Session_BrowseSafe
ReadSaferead_safereadSafeReadSaferead_safeDarraUa_Session_ReadSafe
WriteSafewrite_safewriteSafeWriteSafewrite_safeDarraUa_Session_WriteSafe
CallSafecall_safecallSafeCallSafecall_safeDarraUa_Session_CallSafe
ReadHistorySaferead_history_safereadHistorySafeReadHistorySaferead_history_safeDarraUa_Session_ReadHistorySafe

下一步