using HslCommunication; using MoviconHub.App.Com; using MoviconHub.App.Models; using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MoviconHub.App.Services { /// /// WebSocket客户端类,基于HslCommunication库实现 /// public class WebSocketClient : IDisposable { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly WebSocketConfig _config; private HslCommunication.WebSocket.WebSocketClient _client; private Timer _heartbeatTimer; private Timer _reconnectTimer; private bool _isConnected = false; private bool _reconnecting = false; private bool _disposed = false; private int _reconnectAttempts = 0; private readonly int _maxReconnectInterval = 300000; // 最大重连间隔,默认5分钟 private readonly object _lockObject = new object(); // 事件定义 public event EventHandler MessageReceived; public event EventHandler Connected; public event EventHandler Disconnected; public event EventHandler Error; /// /// 初始化WebSocket客户端 /// public WebSocketClient() { _config = WebSocketConfig.LoadConfig(); InitializeClient(); } /// /// 初始化WebSocket客户端 /// private void InitializeClient() { try { // 初始化客户端并设置服务器地址和端口 _client = new HslCommunication.WebSocket.WebSocketClient(_config.ServerAddress, _config.ServerPort, _config.Url); // 设置日志记录器 _client.LogNet = new HslCommunication.LogNet.LogNetSingle("websocket_logs.txt"); // 注册消息接收事件处理 _client.OnClientApplicationMessageReceive += (message) => { try { Logger.Debug($"收到消息: {message.ToString()}"); // 尝试解析消息 MoviconHub.App.Models.WebSocketMessage wsMessage = JsonConvert.DeserializeObject(message.ToString()); if (wsMessage != null) { // 触发消息接收事件 MessageReceived?.Invoke(this, new MoviconHub.App.Models.WebSocketMessageEventArgs { Message = wsMessage, RawMessage = message.ToString() }); } } catch (Exception ex) { Logger.Error(ex, "处理接收到的WebSocket消息时发生错误"); } }; // 注册连接成功事件 _client.OnClientConnected += () => { Logger.Info($"已成功连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort}"); _isConnected = true; // 启动心跳定时器 //StartHeartbeatTimer(); // 触发连接事件 Connected?.Invoke(this, new WebSocketConnectEventArgs { ServerAddress = _config.ServerAddress, ServerPort = _config.ServerPort, IsReconnection = _reconnectAttempts > 0 }); }; // 注册网络错误事件 - 根据文档示例调整参数 _client.OnNetworkError += (sender, e) => { string errorMessage = "WebSocket网络连接错误"; Logger.Error(errorMessage); HandleDisconnection(); Error?.Invoke(this, new WebSocketErrorEventArgs { ErrorMessage = errorMessage }); }; } catch (Exception ex) { Logger.Error(ex, "初始化WebSocket客户端时发生错误"); } } /// /// 连接到WebSocket服务器 /// /// 连接结果 public async Task ConnectAsync() { if (_disposed) throw new ObjectDisposedException(nameof(WebSocketClient)); if (_isConnected) return true; try { lock (_lockObject) { if (_isConnected) return true; _reconnecting = false; _reconnectAttempts = 0; } // 确保设置了服务器地址和端口 _client.IpAddress = _config.ServerAddress; _client.Port = _config.ServerPort; Logger.Info($"正在连接到WebSocket服务器: ws://{_config.ServerAddress}:{_config.ServerPort}"); // 创建一个任务来包装同步连接方法 var tcs = new TaskCompletionSource(); var connectTask = Task.Run(() => { try { var result = _client.ConnectServer(); if (result.IsSuccess) { tcs.SetResult(true); } else { Logger.Warn($"WebSocket连接失败: {result.Message}"); tcs.SetResult(false); } } catch (Exception ex) { Logger.Error(ex, "WebSocket连接过程中发生异常"); tcs.SetResult(false); } }); // 添加超时控制 var timeoutTask = Task.Delay(_config.ConnectionTimeout); var completedTask = await Task.WhenAny(tcs.Task, timeoutTask); if (completedTask == timeoutTask) { Logger.Warn($"连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort} 超时"); Error?.Invoke(this, new WebSocketErrorEventArgs { Exception = new TimeoutException("WebSocket连接超时"), ErrorMessage = "连接超时" }); if (_config.AutoReconnect) StartReconnectTimer(); return false; } bool connectionSuccess = await tcs.Task; if (!connectionSuccess && _config.AutoReconnect) { StartReconnectTimer(); } return connectionSuccess; } catch (Exception ex) { Logger.Error(ex, $"连接到WebSocket服务器 {_config.ServerAddress}:{_config.ServerPort} 时发生错误"); Error?.Invoke(this, new WebSocketErrorEventArgs { Exception = ex, ErrorMessage = ex.Message }); if (_config.AutoReconnect) StartReconnectTimer(); return false; } } /// /// 断开与WebSocket服务器的连接 /// public void Disconnect() { if (_disposed) return; try { // 停止定时器 StopHeartbeatTimer(); StopReconnectTimer(); if (_isConnected) { _client.ConnectClose(); _isConnected = false; Logger.Info("已断开与WebSocket服务器的连接"); Disconnected?.Invoke(this, new WebSocketConnectEventArgs { ServerAddress = _config.ServerAddress, ServerPort = _config.ServerPort, IsReconnection = false }); } } catch (Exception ex) { Logger.Error(ex, "断开WebSocket连接时发生错误"); } } /// /// 发送消息 /// /// 要发送的消息 /// 是否发送成功 public bool SendMessage(MoviconHub.App.Models.WebSocketMessage message) { if (_disposed) throw new ObjectDisposedException(nameof(WebSocketClient)); if (!_isConnected) { Logger.Warn("未连接到WebSocket服务器,无法发送消息"); return false; } try { string json = JsonConvert.SerializeObject(message); var sendResult = _client.SendServer(json); if (sendResult.IsSuccess) { Logger.Debug($"消息已发送: {json}"); return true; } else { Logger.Warn($"发送消息失败: {sendResult.Message}"); HandleDisconnection(); return false; } } catch (Exception ex) { Logger.Error(ex, "发送WebSocket消息时发生错误"); HandleDisconnection(); return false; } } /// /// 发送设备数据 /// 全量数据 /// /// 状态数据 /// 是否发送成功 public bool SendDeviceData(WebSocketData webSocketData) { MoviconHub.App.Models.WebSocketMessage message = MoviconHub.App.Models.WebSocketMessage.CreateDeviceData( webSocketData); return SendMessage(message); } /// /// 发送设备状态数据 /// /// 状态数据 /// 是否发送成功 public bool SendDeviceStatus(DeviceStatusData statusData) { MoviconHub.App.Models.WebSocketMessage message = MoviconHub.App.Models.WebSocketMessage.CreateDeviceStatusMessage(_config.DeviceCode, statusData); return SendMessage(message); } /// /// 发送设备故障信息 /// /// 故障数据 /// 是否发送成功 public bool SendDeviceFault(FaultDetails faultData) { MoviconHub.App.Models.WebSocketMessage message = MoviconHub.App.Models.WebSocketMessage.CreateFaultMessage(_config.DeviceCode, faultData); return SendMessage(message); } /// /// 发送测试数据 /// /// 测试数据 /// 是否发送成功 public bool SendTestData(TestData testData) { MoviconHub.App.Models.WebSocketMessage message = MoviconHub.App.Models.WebSocketMessage.CreateTestDataMessage(_config.DeviceCode, testData); return SendMessage(message); } /// /// 更新配置 /// /// 服务器地址 /// 端口 /// 设备编码 /// 是否重连 public async Task UpdateConfig(string serverAddress, int port, string deviceCode, bool reconnect = true) { bool wasConnected = _isConnected; if (wasConnected) Disconnect(); _config.ServerAddress = serverAddress; _config.ServerPort = port; _config.DeviceCode = deviceCode; _config.SaveConfig(); // 重新创建客户端 _client.ConnectClose(); InitializeClient(); if (wasConnected && reconnect) await ConnectAsync(); } /// /// 处理断开连接情况 /// private void HandleDisconnection() { if (!_isConnected) return; lock (_lockObject) { if (!_isConnected) return; _isConnected = false; StopHeartbeatTimer(); Logger.Warn("WebSocket连接已断开"); Disconnected?.Invoke(this, new WebSocketConnectEventArgs { ServerAddress = _config.ServerAddress, ServerPort = _config.ServerPort, IsReconnection = false }); if (_config.AutoReconnect && !_reconnecting) { StartReconnectTimer(); } } } /// /// 启动心跳定时器 /// private void StartHeartbeatTimer() { StopHeartbeatTimer(); _heartbeatTimer = new Timer(SendHeartbeat, null, _config.HeartbeatInterval, _config.HeartbeatInterval); Logger.Debug($"心跳定时器已启动,间隔: {_config.HeartbeatInterval}毫秒"); } /// /// 停止心跳定时器 /// private void StopHeartbeatTimer() { _heartbeatTimer?.Dispose(); _heartbeatTimer = null; } /// /// 发送心跳消息 /// private void SendHeartbeat(object state) { if (!_isConnected) return; try { MoviconHub.App.Models.WebSocketMessage heartbeat = MoviconHub.App.Models.WebSocketMessage.CreateHeartbeat(_config.DeviceCode); SendMessage(heartbeat); Logger.Debug("已发送心跳消息"); } catch (Exception ex) { Logger.Error(ex, "发送心跳消息时发生错误"); } } /// /// 启动重连定时器 /// private void StartReconnectTimer() { lock (_lockObject) { if (_reconnecting) return; _reconnecting = true; StopReconnectTimer(); _reconnectTimer = new Timer(ReconnectCallback, null, _config.ReconnectInterval, Timeout.Infinite); // 只执行一次,在重连方法中再次设置定时器 Logger.Info($"重连定时器已启动,间隔: {_config.ReconnectInterval}毫秒"); } } /// /// 重连回调方法 /// private void ReconnectCallback(object stateObj) { if (_isConnected || _disposed) return; // 使用Task执行异步重连 Task.Run(async () => { await ReconnectAsync(); }); } /// /// 停止重连定时器 /// private void StopReconnectTimer() { _reconnectTimer?.Dispose(); _reconnectTimer = null; } /// /// 执行重连 /// private async Task ReconnectAsync() { if (_isConnected || _disposed) return; _reconnectAttempts++; Logger.Info($"正在尝试重连,第 {_reconnectAttempts} 次"); bool success = await ConnectAsync(); if (!success && _config.AutoReconnect && !_disposed) { lock (_lockObject) { if (!_isConnected && !_disposed) { // 计算指数退避重连间隔 int nextInterval = Math.Min( _config.ReconnectInterval * (int)Math.Pow(2, Math.Min(9, _reconnectAttempts - 1)), // 最多512倍,避免间隔过长 _maxReconnectInterval); // 最大重试间隔 Logger.Info($"重连失败,{nextInterval}毫秒后将再次重试"); _reconnectTimer = new Timer(ReconnectCallback, null, nextInterval, Timeout.Infinite); } } } else if (success) { _reconnecting = false; } } /// /// 是否已连接 /// public bool IsConnected => _isConnected; /// /// 释放资源 /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// /// 释放资源 /// /// 是否由Dispose调用 protected virtual void Dispose(bool disposing) { if (_disposed) return; if (disposing) { // 释放托管资源 Disconnect(); _heartbeatTimer?.Dispose(); _reconnectTimer?.Dispose(); _client?.Dispose(); } _disposed = true; } } }