自动重连 + RetryOnSessionFault
概述
OPC UA Server 因维护重启 / 网络抖动 / 心跳超时会让客户端 Session 失效。SDK 内部把所有 RPC (Read/Write/Browse/Call/ReadHistory/...) 都用 RetryOnSessionFault(...) 包了一层:
- 调底层 native RPC, 命中
BadSessionClosed/BadSessionIdInvalid/BadSecureChannelClosed之一 - 自动调
Reconnect()重建 SecureChannel + Session + ActivateSession - 重连成功后 重试一次业务调用
- 重试仍失败 → 抛原始
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 在重连成功后会自动:
- 尝试
TransferSubscriptions(oldSubId)把旧 Subscription 转给新 Session - 转移失败 → 用缓存的
MonitoredItemSpec重建所有 MonitoredItem (含 DataChangeFilter / EventFilter)
详见 订阅自恢复。
最佳实践
- 不要在业务代码里写重连 try/catch — 让 SDK 处理, 业务专注业务
- 挂 Events 给 UI — 用户需要看到"正在重连..."而不是界面假死
- 关键操作前查
ua.State— 例如 Write 关键参数前确认State == Connected - 不要在 UI 线程调用
Reconnect()— 重连可能耗时数秒, 用Task.Run包一下 - 测试时主动断开网线 5 秒, 看日志里的
Reconnecting → Reconnected是否如期出现
跨语言对照
| C# | Python | Java | C++ | Rust | C |
|---|---|---|---|---|---|
| ua.Reconnect() | ua.reconnect() | ua.reconnect() | ua.Reconnect() | ua.reconnect() | DarraUa_Session_Reconnect |
| ua.Events.Reconnecting | events.on('reconnecting', ...) | events.onReconnecting(...) | events.OnReconnecting(...) | events.on_reconnecting(...) | DarraUa_RegisterReconnectingHandler |