using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using NLog; using TouchSocket.Core; using TouchSocket.Sockets; namespace FATrace.OEMApp.Services { /// /// TouchSocket 服务器 - 基于 TouchSocket 实现的多客户端 TCP 服务器 /// 功能:接收客户端数据、解析为字符串、触发事件通知外部、支持向客户端发送数据 /// 协议:使用 CRLF (\r\n) 作为行分隔符的文本协议 /// 编码:UTF-8 /// public class TouchSocketServer { /// /// 构造函数 /// /// /// /// /// public TouchSocketServer(string listenIp, int listenPort, int receiveTimeout, int sendTimeout) { ListenIp = listenIp; ListenPort = listenPort; ReceiveTimeout = receiveTimeout; SendTimeout = sendTimeout; } #region 私有字段 /// /// NLog 日志记录器 /// private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); /// /// TouchSocket TCP 服务实例 /// private TcpService _service; /// /// 服务器是否正在运行 /// private bool _isRunning = false; /// /// 已连接的客户端字典(ClientId -> dynamic) /// 用于快速查找和管理客户端 /// 使用 dynamic 类型以兼容 TouchSocket 4.0 的客户端类型 /// private readonly ConcurrentDictionary _clients = new ConcurrentDictionary(); #endregion #region 公共属性 /// /// 服务器监听 IP 地址 /// 默认:127.0.0.1(本地回环) /// 0.0.0.0 表示监听所有网卡 /// public string ListenIp { get; set; } = "127.0.0.1"; /// /// 服务器监听端口 /// 默认:6001 /// public int ListenPort { get; set; } = 6001; /// /// 接收超时时间(毫秒) /// 默认:30000 毫秒(30秒) /// 如果客户端在此时间内无数据交互,连接将被关闭 /// public int ReceiveTimeout { get; set; } = 30000; /// /// 发送超时时间(毫秒) /// 默认:30000 毫秒(30秒) /// public int SendTimeout { get; set; } = 30000; /// /// 缓冲区大小(字节) /// 默认:1024 * 64(64KB) /// public int BufferLength { get; set; } = 1024 * 64; /// /// 最大连接数 /// 默认:10000 /// public int MaxCount { get; set; } = 10000; /// /// 服务器是否正在运行 /// public bool IsRunning => _isRunning; /// /// 当前连接的客户端数量 /// public int ConnectedClientCount => _clients.Count; #endregion #region 事件定义 /// /// 数据接收事件参数 /// public class DataReceivedEventArgs : EventArgs { /// /// 客户端 ID(唯一标识) /// public string? ClientId { get; set; } /// /// 客户端 IP 地址 /// public string? RemoteIp { get; set; } /// /// 客户端端口 /// public int RemotePort { get; set; } /// /// 接收到的数据(已解析为字符串) /// public string? Data { get; set; } /// /// 接收时间 /// public DateTime ReceivedTime { get; set; } } /// /// 客户端连接事件参数 /// public class ClientConnectedEventArgs : EventArgs { /// /// 客户端 ID /// public string? ClientId { get; set; } /// /// 客户端 IP 地址 /// public string? RemoteIp { get; set; } /// /// 客户端端口 /// public int RemotePort { get; set; } /// /// 连接时间 /// public DateTime ConnectedTime { get; set; } } /// /// 客户端断开事件参数 /// public class ClientDisconnectedEventArgs : EventArgs { /// /// 客户端 ID /// public string? ClientId { get; set; } /// /// 客户端 IP 地址 /// public string? RemoteIp { get; set; } /// /// 客户端端口 /// public int RemotePort { get; set; } /// /// 断开时间 /// public DateTime DisconnectedTime { get; set; } /// /// 断开原因 /// public string? Reason { get; set; } } /// /// 数据接收事件 /// 当接收到客户端数据时触发,外部可订阅此事件进行业务处理 /// public event EventHandler DataReceived; /// /// 客户端连接事件 /// 当有新客户端连接时触发 /// public event EventHandler ClientConnected; /// /// 客户端断开事件 /// 当客户端断开连接时触发 /// public event EventHandler ClientDisconnected; /// /// 服务器错误事件 /// 当服务器发生错误时触发 /// public event EventHandler ServerError; #endregion #region 公共方法 /// /// 启动 Socket 服务器 /// /// 启动是否成功 public async Task StartAsync() { try { // 检查是否已经在运行 if (_isRunning) { Logger.Warn("Socket 服务器已经在运行中,无需重复启动"); return true; } Logger.Info($"正在启动 Socket 服务器,监听地址:{ListenIp}:{ListenPort},超时时间:{ReceiveTimeout}毫秒"); // 创建 TouchSocket 服务实例 _service = new TcpService(); // 配置连接事件 _service.Connecting = (client, e) => { Logger.Debug($"客户端正在连接:{client.Id},远程地址:{client.IP}:{client.Port}"); return EasyTask.CompletedTask; }; // 配置连接成功事件 _service.Connected = (client, e) => { try { // 添加到客户端字典 _clients.TryAdd(client.Id, client); // 记录连接日志 Logger.Info($"客户端已连接,ClientId={client.Id},远程地址={client.IP}:{client.Port},当前连接数={ConnectedClientCount}"); // 触发客户端连接事件 OnClientConnected(new ClientConnectedEventArgs { ClientId = client.Id, RemoteIp = client.IP, RemotePort = client.Port, ConnectedTime = DateTime.Now }); } catch (Exception ex) { Logger.Error(ex, $"处理客户端连接时发生异常:ClientId={client.Id},错误={ex.Message}"); OnServerError(ex); } return EasyTask.CompletedTask; }; // 配置断开连接事件 _service.Closed = (client, e) => { try { // 从客户端字典中移除 _clients.TryRemove(client.Id, out _); // 记录断开日志 Logger.Info($"客户端已断开,ClientId={client.Id},远程地址={client.IP}:{client.Port},原因={e.Message},当前连接数={ConnectedClientCount}"); // 触发客户端断开事件 OnClientDisconnected(new ClientDisconnectedEventArgs { ClientId = client.Id, RemoteIp = client.IP, RemotePort = client.Port, DisconnectedTime = DateTime.Now, Reason = e.Message }); } catch (Exception ex) { Logger.Error(ex, $"处理客户端断开时发生异常:ClientId={client.Id},错误={ex.Message}"); OnServerError(ex); } return EasyTask.CompletedTask; }; // 配置数据接收事件 _service.Received = (client, e) => { try { // 解析数据为字符串 // TouchSocket 4.0 使用 e.Memory 获取数据 var data = Encoding.UTF8.GetString(e.Memory.Span); // 记录接收日志 Logger.Debug($"接收到客户端数据,ClientId={client.Id},远程地址={client.IP}:{client.Port},数据长度={data.Length}字符,内容={data}"); // 触发数据接收事件 OnDataReceived(new DataReceivedEventArgs { ClientId = client.Id, RemoteIp = client.IP, RemotePort = client.Port, Data = data, ReceivedTime = DateTime.Now }); } catch (Exception ex) { Logger.Error(ex, $"处理接收数据时发生异常:ClientId={client.Id},错误={ex.Message}"); OnServerError(ex); } return EasyTask.CompletedTask; }; // 配置服务器 var config = new TouchSocketConfig(); config.SetListenIPHosts($"tcp://{ListenIp}:{ListenPort}") .SetMaxCount(MaxCount); // 设置最大连接数 // 应用配置并启动服务器 await _service.SetupAsync(config); await _service.StartAsync(); _isRunning = true; Logger.Info($"Socket 服务器启动成功,监听地址:{ListenIp}:{ListenPort}"); return true; } catch (Exception ex) { Logger.Error(ex, $"启动 Socket 服务器时发生异常:{ex.Message}"); OnServerError(ex); return false; } } /// /// 停止 Socket 服务器 /// public async Task StopAsync() { try { if (!_isRunning || _service == null) { Logger.Warn("Socket 服务器未运行,无需停止"); return; } Logger.Info("正在停止 Socket 服务器..."); _isRunning = false; // 停止服务器 await _service?.StopAsync(); _service?.Dispose(); _service = null; // 清空客户端字典 _clients.Clear(); Logger.Info("Socket 服务器已停止"); } catch (Exception ex) { Logger.Error(ex, $"停止 Socket 服务器时发生异常:{ex.Message}"); OnServerError(ex); } } /// /// 向指定客户端发送数据 /// /// 客户端 ID(唯一标识) /// 要发送的字符串数据 /// 发送是否成功 public bool SendToClient(string clientId, string data) { try { // 参数校验 if (string.IsNullOrWhiteSpace(clientId)) { Logger.Warn("发送数据失败:ClientId 为空"); return false; } if (string.IsNullOrEmpty(data)) { Logger.Warn($"发送数据失败:数据为空,ClientId={clientId}"); return false; } if (_service == null || !_isRunning) { Logger.Warn($"发送数据失败:服务器未运行或服务实例为空,ClientId={clientId}"); return false; } // 可选:先检查是否存在该客户端,便于输出更友好的日志 //if (!_clients.ContainsKey(clientId)) //{ // Logger.Warn($"发送数据失败:未找到客户端,ClientId={clientId}"); // return false; //} // 发送数据(自动添加 CRLF 行结束符) var dataToSend = data.EndsWith("\r\n") ? data : data + "\r\n"; var buffer = Encoding.UTF8.GetBytes(dataToSend); // 使用 TcpService 的 SendAsync(id, buffer) 按会话 Id 发送 _service.SendAsync(clientId, buffer).GetAwaiter().GetResult(); Logger.Debug($"向客户端发送数据成功,ClientId={clientId},数据长度={buffer.Length}字节,内容={data}"); return true; } catch (Exception ex) { Logger.Error(ex, $"向客户端发送数据时发生异常:ClientId={clientId},错误={ex.Message}"); OnServerError(ex); return false; } } /// /// 向所有已连接的客户端广播数据 /// /// 要广播的字符串数据 /// 成功发送的客户端数量 public int Broadcast(string data) { try { if (string.IsNullOrEmpty(data)) { Logger.Warn("广播数据失败:数据为空"); return 0; } // 获取所有客户端 var clientList = _clients.Values.ToList(); if (clientList.Count == 0) { Logger.Debug("广播数据:当前无已连接的客户端"); return 0; } // 准备数据 var dataToSend = data.EndsWith("\r\n") ? data : data + "\r\n"; var buffer = Encoding.UTF8.GetBytes(dataToSend); // 向所有客户端发送 int successCount = 0; if (_service == null || !_isRunning) { Logger.Warn("广播数据失败:服务器未运行或服务实例为空"); return 0; } foreach (var client in clientList) { try { // 使用 TcpService.SendAsync 通过客户端 Id 发送 _service.SendAsync(client.Id, buffer).GetAwaiter().GetResult(); successCount++; } catch (Exception ex) { Logger.Error(ex, $"向客户端广播数据失败:ClientId={client.Id},错误={ex.Message}"); } } Logger.Info($"广播数据完成,成功发送到 {successCount}/{clientList.Count} 个客户端,数据长度={buffer.Length}字节"); return successCount; } catch (Exception ex) { Logger.Error(ex, $"广播数据时发生异常:{ex.Message}"); OnServerError(ex); return 0; } } /// /// 断开指定客户端的连接 /// /// 客户端 ID /// 断开是否成功 public bool DisconnectClient(string clientId) { try { if (string.IsNullOrWhiteSpace(clientId)) { Logger.Warn("断开客户端失败:ClientId 为空"); return false; } if (!_clients.TryGetValue(clientId, out var client)) { Logger.Warn($"断开客户端失败:未找到客户端,ClientId={clientId}"); return false; } client.Close("服务器主动断开"); Logger.Info($"已主动断开客户端连接,ClientId={clientId}"); return true; } catch (Exception ex) { Logger.Error(ex, $"断开客户端连接时发生异常:ClientId={clientId},错误={ex.Message}"); OnServerError(ex); return false; } } /// /// 获取所有已连接客户端的 ID 列表 /// /// 客户端 ID 列表 public List GetConnectedClientIds() { return _clients.Keys.ToList(); } /// /// 获取指定客户端的详细信息 /// /// 客户端 ID /// 客户端信息字符串,如果未找到返回 null public string GetClientInfo(string clientId) { if (_clients.TryGetValue(clientId, out var client)) { return $"ClientId={client.Id}, IP={client.IP}:{client.Port}, 在线={client.Online}"; } return null; } #endregion #region 私有方法 - 事件触发 /// /// 触发数据接收事件 /// private void OnDataReceived(DataReceivedEventArgs e) { try { DataReceived?.Invoke(this, e); } catch (Exception ex) { Logger.Error(ex, $"触发 DataReceived 事件时发生异常:{ex.Message}"); } } /// /// 触发客户端连接事件 /// private void OnClientConnected(ClientConnectedEventArgs e) { try { ClientConnected?.Invoke(this, e); } catch (Exception ex) { Logger.Error(ex, $"触发 ClientConnected 事件时发生异常:{ex.Message}"); } } /// /// 触发客户端断开事件 /// private void OnClientDisconnected(ClientDisconnectedEventArgs e) { try { ClientDisconnected?.Invoke(this, e); } catch (Exception ex) { Logger.Error(ex, $"触发 ClientDisconnected 事件时发生异常:{ex.Message}"); } } /// /// 触发服务器错误事件 /// private void OnServerError(Exception ex) { try { ServerError?.Invoke(this, ex); } catch (Exception eventEx) { Logger.Error(eventEx, $"触发 ServerError 事件时发生异常:{eventEx.Message}"); } } #endregion } }