using System; using System.Threading; using System.Threading.Tasks; using Serilog; namespace Protocol376Simulator.Services { /// /// 重连服务类,负责处理自动重连逻辑 /// public class ReconnectionService { private readonly NetworkService _networkService; private readonly string _deviceIdentifier; private CancellationTokenSource _reconnectCancellationTokenSource; private Task _reconnectTask; private readonly object _reconnectLock = new object(); // 重连配置 private bool _autoReconnect = true; private int _reconnectAttempts = 0; private int _maxReconnectAttempts = 5; private TimeSpan _reconnectDelay = TimeSpan.FromSeconds(5); private TimeSpan _reconnectIncreaseDelay = TimeSpan.FromSeconds(5); private DateTime _lastReconnectTime = DateTime.MinValue; private TimeSpan _minReconnectInterval = TimeSpan.FromSeconds(30); private bool _isReconnecting = false; /// /// 当重连尝试开始时触发 /// public event EventHandler ReconnectAttemptStarted; /// /// 当重连尝试结束时触发 /// public event EventHandler ReconnectAttemptCompleted; /// /// 是否启用自动重连 /// public bool AutoReconnect { get => _autoReconnect; set => _autoReconnect = value; } /// /// 重连尝试次数 /// public int ReconnectAttempts => _reconnectAttempts; /// /// 是否正在重连 /// public bool IsReconnecting => _isReconnecting; /// /// 构造函数 /// /// 网络服务 /// 设备标识(用于日志) public ReconnectionService(NetworkService networkService, string deviceIdentifier) { _networkService = networkService ?? throw new ArgumentNullException(nameof(networkService)); _deviceIdentifier = deviceIdentifier; // 订阅网络服务的连接状态变更事件 _networkService.ConnectionStatusChanged += OnConnectionStatusChanged; } /// /// 设置重连参数 /// /// 是否启用自动重连 /// 最大重连尝试次数 /// 重连延迟(秒) public void SetReconnectParameters(bool autoReconnect, int maxAttempts, int delaySeconds) { _autoReconnect = autoReconnect; _maxReconnectAttempts = maxAttempts; _reconnectDelay = TimeSpan.FromSeconds(delaySeconds); _reconnectIncreaseDelay = TimeSpan.FromSeconds(delaySeconds); Log.Information("{DeviceId} 已设置重连参数: 自动重连={AutoReconnect}, 最大尝试次数={MaxAttempts}, 延迟={Delay}秒", _deviceIdentifier, _autoReconnect, _maxReconnectAttempts, delaySeconds); } /// /// 连接状态变更处理 /// private void OnConnectionStatusChanged(object sender, NetworkService.ConnectionStatus status) { if (status == NetworkService.ConnectionStatus.Failed || status == NetworkService.ConnectionStatus.Disconnected) { // 如果启用了自动重连,开始重连任务 if (_autoReconnect) { StartReconnectAsync(); } } else if (status == NetworkService.ConnectionStatus.Connected) { // 连接成功,重置重连尝试次数 _reconnectAttempts = 0; StopReconnect(); } } /// /// 开始重连任务 /// private void StartReconnectAsync() { lock (_reconnectLock) { // 如果已经在重连中,不要重复启动 if (_isReconnecting) { return; } // 如果距离上次重连时间太短,不要立即重连 TimeSpan timeSinceLastReconnect = DateTime.Now - _lastReconnectTime; if (timeSinceLastReconnect < _minReconnectInterval) { Log.Information("{DeviceId} 距离上次重连尝试时间太短,将等待 {WaitTime} 秒后再尝试", _deviceIdentifier, (_minReconnectInterval - timeSinceLastReconnect).TotalSeconds); // 等待一段时间后再次检查是否需要重连 Task.Delay(_minReconnectInterval - timeSinceLastReconnect) .ContinueWith(_ => StartReconnectAsync()); return; } _isReconnecting = true; _reconnectCancellationTokenSource?.Cancel(); _reconnectCancellationTokenSource = new CancellationTokenSource(); _reconnectTask = ReconnectAsync(_reconnectCancellationTokenSource.Token); } } /// /// 停止重连任务 /// private void StopReconnect() { lock (_reconnectLock) { _reconnectCancellationTokenSource?.Cancel(); _isReconnecting = false; } } /// /// 重连任务实现 /// private async Task ReconnectAsync(CancellationToken cancellationToken) { // 记录开始重连的时间 _lastReconnectTime = DateTime.Now; while (!cancellationToken.IsCancellationRequested) { _reconnectAttempts++; // 检查是否超过最大尝试次数 if (_maxReconnectAttempts > 0 && _reconnectAttempts > _maxReconnectAttempts) { Log.Warning("{DeviceId} 已达到最大重连尝试次数 {MaxAttempts},停止重连", _deviceIdentifier, _maxReconnectAttempts); lock (_reconnectLock) { _isReconnecting = false; } ReconnectAttemptCompleted?.Invoke(this, false); return; } Log.Information("{DeviceId} 尝试重连 (第 {Attempt}/{MaxAttempts} 次)...", _deviceIdentifier, _reconnectAttempts, _maxReconnectAttempts > 0 ? _maxReconnectAttempts.ToString() : "∞"); // 触发重连开始事件 ReconnectAttemptStarted?.Invoke(this, _reconnectAttempts); try { // 尝试重新连接 await _networkService.ConnectAsync(); // 如果连接成功,退出重连循环 Log.Information("{DeviceId} 重连成功", _deviceIdentifier); lock (_reconnectLock) { _isReconnecting = false; } // 触发重连完成事件 ReconnectAttemptCompleted?.Invoke(this, true); return; } catch (Exception ex) { Log.Warning("{DeviceId} 重连失败: {ErrorMessage}", _deviceIdentifier, ex.Message); // 触发重连完成事件(失败) ReconnectAttemptCompleted?.Invoke(this, false); } // 计算下一次重连的延迟时间(逐渐增加) TimeSpan currentDelay = TimeSpan.FromMilliseconds( _reconnectDelay.TotalMilliseconds + (_reconnectAttempts - 1) * _reconnectIncreaseDelay.TotalMilliseconds); Log.Information("{DeviceId} 将在 {Delay} 秒后重试...", _deviceIdentifier, currentDelay.TotalSeconds); // 等待一段时间后重试 try { await Task.Delay(currentDelay, cancellationToken); } catch (OperationCanceledException) { // 任务被取消,退出循环 break; } } // 如果是因为取消而退出循环 if (cancellationToken.IsCancellationRequested) { lock (_reconnectLock) { _isReconnecting = false; } Log.Information("{DeviceId} 重连任务已取消", _deviceIdentifier); } } /// /// 强制立即尝试重连 /// public async Task ForceReconnectAsync() { // 停止当前的重连任务 StopReconnect(); // 等待一段时间确保任务停止 await Task.Delay(100); // 重置计数并开始新的重连 _reconnectAttempts = 0; StartReconnectAsync(); } } }