跳到主要内容

自动重连 + RetryOnSessionFault

概述

OPC UA Server 因维护重启 / 网络抖动 / 心跳超时会让客户端 Session 失效。SDK 内部把所有 RPC (Read/Write/Browse/Call/ReadHistory/...) 都用 RetryOnSessionFault(...) 包了一层:

  1. 调底层 native RPC, 命中 BadSessionClosed / BadSessionIdInvalid / BadSecureChannelClosed 之一
  2. 自动调 Reconnect() 重建 SecureChannel + Session + ActivateSession
  3. 重连成功后 重试一次业务调用
  4. 重试仍失败 → 抛原始 OpcUaException (Safe 版本则折叠为 StatusCode)

业务侧 无需 显式处理重连。重连结果通过 ua.Events 通道推 Reconnecting / Reconnected 让 UI 切状态栏。

对应规范段: Part 4 §5.6 (SecureChannel) / §5.7 (Session)。

触发条件

下列任一异常 / StatusCode 会触发重连:

触发源含义
StatusCode.BadSessionClosed (0x80260000)Session 已被服务端关闭
StatusCode.BadSessionIdInvalid (0x80250000)Session ID 失效
StatusCode.BadSecureChannelClosed (0x80860000)SecureChannel 关闭
StatusCode.BadServerNotConnected (0x800D0000)服务端不可达
KeepAlive 心跳连续失败 N 次(默认 3 次, 见构造参数)

API

方法 / 事件类别读写说明
ua.Events.Reconnecting事件重连开始, 业务可暂停 UI
ua.Events.Reconnected事件重连成功, 业务可恢复
ua.Events.Disconnected事件重连失败 / 用户主动 Disconnect
ua.Events.SessionLost事件Session 失效 (重连前的预警, Category=SessionLost)

代码示例

using DarraOpcUa_Client;

using var ua = new DarraOpcUa("opc.tcp://localhost:4840");

// 1) UI 状态栏挂事件
ua.Events.Reconnecting += (s, e) =>
{
statusBar.Text = $"重连中... {e.EndpointUrl}";
statusBar.Foreground = Brushes.Orange;
};
ua.Events.Reconnected += (s, e) =>
{
statusBar.Text = $"已恢复";
statusBar.Foreground = Brushes.Green;
};
ua.Events.SessionLost += (s, e) =>
{
Logger.Warn($"Session 失效: {e.Message} ({e.StatusCode})");
};

ua.Connect();

// 2) 业务代码完全不需要写 try/catch 重连
while (running)
{
var (st, dv) = ua.ReadSafe("ns=2;s=Temp");
// 即使中途服务端重启, ReadSafe 内部已自动重连+重试一次
Thread.Sleep(1000);
}

重连策略

  • 重试次数: 单次 RPC 最多重连 1 次 (避免无限循环占住调用方线程)
  • 重连超时: 与构造时的 connectTimeoutMs 一致 (默认 10000 ms)
  • 多 RPC 并发触发: 内部串行化, 第一条 RPC 触发重连后, 其他 RPC 等待重连结果再继续
  • 完全失败后: 由业务侧决定 — 通常通过 ua.Events.Disconnected 提示用户手动 ua.Reconnect()

手动重连

// 业务侧明确知道服务端恢复了, 强制重连
ua.Reconnect();

// 或者关掉再重新 Connect (不保留订阅)
ua.Disconnect();
ua.Connect();

与订阅自恢复的关系

Session 重连后, 服务端的订阅可能已被清理。SDK 在重连成功后会自动:

  1. 尝试 TransferSubscriptions(oldSubId) 把旧 Subscription 转给新 Session
  2. 转移失败 → 用缓存的 MonitoredItemSpec 重建所有 MonitoredItem (含 DataChangeFilter / EventFilter)

详见 订阅自恢复

最佳实践

  • 不要在业务代码里写重连 try/catch — 让 SDK 处理, 业务专注业务
  • 挂 Events 给 UI — 用户需要看到"正在重连..."而不是界面假死
  • 关键操作前查 ua.State — 例如 Write 关键参数前确认 State == Connected
  • 不要在 UI 线程调用 Reconnect() — 重连可能耗时数秒, 用 Task.Run 包一下
  • 测试时主动断开网线 5 秒, 看日志里的 Reconnecting → Reconnected 是否如期出现

跨语言对照

C#PythonJavaC++RustC
ua.Reconnect()ua.reconnect()ua.reconnect()ua.Reconnect()ua.reconnect()DarraUa_Session_Reconnect
ua.Events.Reconnectingevents.on('reconnecting', ...)events.onReconnecting(...)events.OnReconnecting(...)events.on_reconnecting(...)DarraUa_RegisterReconnectingHandler

下一步