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;
}
}
}