工业现场网络并不稳定,网线松动、网络切换、PLC 重启都会导致 ADS 连接断开。如果上位机没有自动重连机制,工程师必须手动重启软件,这在无人值守的产线上是不可接受的。
本文介绍一套经过半导体设备现场验证的心跳检测 + 指数退避自动重连方案,完整 C# MVVM 实现。
连接状态机包含三个状态:
// IAdsService.cs — 定义通信接口,便于 Mock 测试 public interface IAdsService { bool IsConnected { get; } event Action<bool> ConnectionChanged; Task<T> ReadAsync<T>(string symbolName); Task WriteAsync<T>(string symbolName, T value); }
// AdsService.cs — 指数退避重连(1→2→4→8→15→30s) private int[] _backoffSeconds = { 1, 2, 4, 8, 15, 30 }; private int _retryIndex = 0; private async Task HeartbeatLoopAsync(CancellationToken ct) { while (!ct.IsCancellationRequested) { await Task.Delay(1000, ct); try { var state = await _client.ReadStateAsync(); if (state.AdsState != AdsState.Run) throw new AdsException("PLC not in Run state"); _retryIndex = 0; // 重置退避计数 SetConnected(true); } catch { SetConnected(false); await ReconnectWithBackoffAsync(ct); } } } private async Task ReconnectWithBackoffAsync(CancellationToken ct) { var wait = _backoffSeconds[ Math.Min(_retryIndex, _backoffSeconds.Length - 1)]; _retryIndex++; await Task.Delay(wait * 1000, ct); try { _client.Disconnect(); _client.Connect(_amsNetId, _port); SetConnected(true); _retryIndex = 0; } catch { /* 继续下一轮退避 */ } }
// MainViewModel.cs — 连接状态绑定到 UI public string ConnectionStatus => _adsService.IsConnected ? "● 在线" : "○ 离线"; public string StatusColor => _adsService.IsConnected ? "#2e9e5b" : "#cc3333"; // 构造函数中订阅事件,通过 Dispatcher 回到 UI 线程 _adsService.ConnectionChanged += isConnected => Application.Current.Dispatcher.Invoke(() => { OnPropertyChanged(nameof(ConnectionStatus)); OnPropertyChanged(nameof(StatusColor)); });
💡 重连后必须重新订阅 ADS Notification:连接断线时已注册的 Notification 句柄会失效,重连成功后需重新调用 AddDeviceNotificationAsync,否则实时数据推送会静默失效——这是最常被遗漏的一步。
完整工程源码含 IAdsService 接口、AdsService 实现、Mock 测试类,已上传至 github.com/tc3-engineer。