using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using NLog; namespace FATrace.OEMApp.Services { /// /// Socket 服务器 - 基于原生 TcpListener 实现的多客户端 TCP 服务器 /// 功能:接收客户端数据、解析为字符串、触发事件通知外部、支持向客户端发送数据 /// 协议:使用 CRLF (\r\n) 作为行分隔符的文本协议 /// 编码:UTF-8 /// public class SocketService { #region 私有字段 /// /// NLog 日志记录器 /// private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); /// /// TCP 监听器 /// private TcpListener _listener; /// /// 服务器是否正在运行 /// private bool _isRunning = false; /// /// 取消令牌源,用于停止服务器 /// private CancellationTokenSource _cts; /// /// 已连接的客户端字典(SessionId -> ClientSession) /// 使用线程安全的 ConcurrentDictionary /// private readonly ConcurrentDictionary _clients = new ConcurrentDictionary(); /// /// 会话 ID 计数器 /// private int _sessionIdCounter = 0; #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; /// /// 接收超时时间(秒) /// 默认:30 秒 /// 如果客户端在此时间内无数据交互,连接将被关闭 /// public int ReceiveTimeout { get; set; } = 30; /// /// 发送超时时间(秒) /// 默认:30 秒 /// public int SendTimeout { get; set; } = 30; /// /// 服务器是否正在运行 /// public bool IsRunning => _isRunning; /// /// 当前连接的客户端数量 /// public int ConnectedClientCount { get { return _clients.Count; } } #endregion #region 事件定义 /// /// 数据接收事件参数 /// public class DataReceivedEventArgs : EventArgs { /// /// 会话 ID(客户端唯一标识) /// public string SessionId { 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 SessionId { 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 SessionId { 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}秒"); // 解析 IP 地址 IPAddress ipAddress; if (!IPAddress.TryParse(ListenIp, out ipAddress)) { Logger.Error($"无效的 IP 地址:{ListenIp}"); return false; } // 创建 TCP 监听器 _listener = new TcpListener(ipAddress, ListenPort); _listener.Start(); // 创建取消令牌 _cts = new CancellationTokenSource(); _isRunning = true; Logger.Info($"Socket 服务器启动成功,监听地址:{ListenIp}:{ListenPort}"); // 启动接受客户端连接的任务 _ = Task.Run(() => AcceptClientsAsync(_cts.Token), _cts.Token); return true; } catch (Exception ex) { Logger.Error(ex, $"启动 Socket 服务器时发生异常:{ex.Message}"); OnServerError(ex); return false; } } /// /// 停止 Socket 服务器 /// /// 停止任务 public async Task StopAsync() { try { if (!_isRunning || _listener == null) { Logger.Warn("Socket 服务器未运行,无需停止"); return; } Logger.Info("正在停止 Socket 服务器..."); _isRunning = false; // 取消所有异步操作 _cts?.Cancel(); // 停止监听器 _listener?.Stop(); // 断开所有客户端 foreach (var client in _clients.Values) { try { client.TcpClient?.Close(); } catch (Exception ex) { Logger.Warn(ex, $"关闭客户端连接时发生异常:SessionId={client.SessionId}"); } } // 清空客户端字典 _clients.Clear(); // 释放资源 _cts?.Dispose(); _cts = null; _listener = null; Logger.Info("Socket 服务器已停止"); await Task.CompletedTask; } catch (Exception ex) { Logger.Error(ex, $"停止 Socket 服务器时发生异常:{ex.Message}"); OnServerError(ex); } } /// /// 向指定客户端发送数据 /// /// 会话 ID(客户端唯一标识) /// 要发送的字符串数据 /// 发送是否成功 public async Task SendToClientAsync(string sessionId, string data) { try { // 参数校验 if (string.IsNullOrWhiteSpace(sessionId)) { Logger.Warn("发送数据失败:SessionId 为空"); return false; } if (string.IsNullOrEmpty(data)) { Logger.Warn($"发送数据失败:数据为空,SessionId={sessionId}"); return false; } // 查找会话 if (!_clients.TryGetValue(sessionId, out var client)) { Logger.Warn($"发送数据失败:未找到会话,SessionId={sessionId}"); return false; } // 发送数据(自动添加 CRLF 行结束符) var dataToSend = data.EndsWith("\r\n") ? data : data + "\r\n"; var buffer = Encoding.UTF8.GetBytes(dataToSend); await client.Stream.WriteAsync(buffer, 0, buffer.Length); await client.Stream.FlushAsync(); Logger.Debug($"向客户端发送数据成功,SessionId={sessionId},数据长度={buffer.Length}字节,内容={data}"); return true; } catch (Exception ex) { Logger.Error(ex, $"向客户端发送数据时发生异常:SessionId={sessionId},错误={ex.Message}"); OnServerError(ex); return false; } } /// /// 向所有已连接的客户端广播数据 /// /// 要广播的字符串数据 /// 成功发送的客户端数量 public async Task BroadcastAsync(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; foreach (var client in clientList) { try { await client.Stream.WriteAsync(buffer, 0, buffer.Length); await client.Stream.FlushAsync(); successCount++; } catch (Exception ex) { Logger.Error(ex, $"向客户端广播数据失败:SessionId={client.SessionId},错误={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 async Task DisconnectClientAsync(string sessionId) { try { if (string.IsNullOrWhiteSpace(sessionId)) { Logger.Warn("断开客户端失败:SessionId 为空"); return false; } if (!_clients.TryGetValue(sessionId, out var client)) { Logger.Warn($"断开客户端失败:未找到会话,SessionId={sessionId}"); return false; } client.TcpClient?.Close(); _clients.TryRemove(sessionId, out _); Logger.Info($"已主动断开客户端连接,SessionId={sessionId}"); return true; } catch (Exception ex) { Logger.Error(ex, $"断开客户端连接时发生异常:SessionId={sessionId},错误={ex.Message}"); OnServerError(ex); return false; } } /// /// 获取所有已连接客户端的会话 ID 列表 /// /// 会话 ID 列表 public List GetConnectedSessionIds() { return _clients.Keys.ToList(); } #endregion #region 私有方法 - 客户端处理 /// /// 接受客户端连接的循环 /// private async Task AcceptClientsAsync(CancellationToken cancellationToken) { Logger.Info("开始接受客户端连接..."); while (!cancellationToken.IsCancellationRequested && _isRunning) { try { // 等待客户端连接 var tcpClient = await _listener.AcceptTcpClientAsync(); // 生成会话 ID var sessionId = $"Session_{Interlocked.Increment(ref _sessionIdCounter)}_{DateTime.Now.Ticks}"; // 获取客户端信息 var remoteEndPoint = tcpClient.Client.RemoteEndPoint as IPEndPoint; var remoteIp = remoteEndPoint?.Address.ToString() ?? "Unknown"; var remotePort = remoteEndPoint?.Port ?? 0; // 创建客户端会话 var clientSession = new ClientSession { SessionId = sessionId, TcpClient = tcpClient, Stream = tcpClient.GetStream(), RemoteIp = remoteIp, RemotePort = remotePort, ConnectedTime = DateTime.Now }; // 添加到客户端字典 if (_clients.TryAdd(sessionId, clientSession)) { Logger.Info($"客户端已连接,SessionId={sessionId},远程地址={remoteIp}:{remotePort},当前连接数={ConnectedClientCount}"); // 触发客户端连接事件 OnClientConnected(new ClientConnectedEventArgs { SessionId = sessionId, RemoteIp = remoteIp, RemotePort = remotePort, ConnectedTime = clientSession.ConnectedTime }); // 启动处理客户端数据的任务 _ = Task.Run(() => HandleClientAsync(clientSession, cancellationToken), cancellationToken); } else { Logger.Warn($"添加客户端会话失败,SessionId={sessionId}"); tcpClient.Close(); } } catch (ObjectDisposedException) { // 监听器已被释放,正常退出 Logger.Info("监听器已关闭,停止接受新连接"); break; } catch (SocketException ex) when (ex.SocketErrorCode == SocketError.Interrupted) { // 监听被中断,正常退出 Logger.Info("监听被中断,停止接受新连接"); break; } catch (Exception ex) { Logger.Error(ex, $"接受客户端连接时发生异常:{ex.Message}"); OnServerError(ex); await Task.Delay(1000, cancellationToken); // 等待一秒后重试 } } Logger.Info("停止接受客户端连接"); } /// /// 处理单个客户端的数据接收 /// private async Task HandleClientAsync(ClientSession client, CancellationToken cancellationToken) { var sessionId = client.SessionId; var stream = client.Stream; var reader = new StreamReader(stream, Encoding.UTF8); Logger.Debug($"开始处理客户端数据,SessionId={sessionId}"); try { // 设置读取超时 stream.ReadTimeout = ReceiveTimeout * 1000; while (!cancellationToken.IsCancellationRequested && _isRunning) { try { // 读取一行数据(以 CRLF 或 LF 结尾) var line = await reader.ReadLineAsync(); // 如果读取到 null,表示连接已关闭 if (line == null) { Logger.Info($"客户端连接已关闭,SessionId={sessionId}"); break; } // 记录接收日志 Logger.Debug($"接收到客户端数据,SessionId={sessionId},远程地址={client.RemoteIp}:{client.RemotePort},数据长度={line.Length}字符,内容={line}"); // 触发数据接收事件 OnDataReceived(new DataReceivedEventArgs { SessionId = sessionId, RemoteIp = client.RemoteIp, RemotePort = client.RemotePort, Data = line, ReceivedTime = DateTime.Now }); } catch (IOException ex) when (ex.InnerException is SocketException socketEx) { // 连接被重置或超时 Logger.Warn($"客户端连接异常,SessionId={sessionId},错误={socketEx.SocketErrorCode}"); break; } catch (IOException ex) { // 读取超时或其他 IO 异常 Logger.Warn(ex, $"读取客户端数据时发生 IO 异常,SessionId={sessionId}"); break; } } } catch (Exception ex) { Logger.Error(ex, $"处理客户端数据时发生异常,SessionId={sessionId},错误={ex.Message}"); OnServerError(ex); } finally { // 清理客户端连接 try { client.TcpClient?.Close(); _clients.TryRemove(sessionId, out _); Logger.Info($"客户端已断开,SessionId={sessionId},远程地址={client.RemoteIp}:{client.RemotePort},当前连接数={ConnectedClientCount}"); // 触发客户端断开事件 OnClientDisconnected(new ClientDisconnectedEventArgs { SessionId = sessionId, RemoteIp = client.RemoteIp, RemotePort = client.RemotePort, DisconnectedTime = DateTime.Now, Reason = "连接关闭" }); } catch (Exception ex) { Logger.Warn(ex, $"清理客户端连接时发生异常,SessionId={sessionId}"); } } } #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 #region 内部类 - 客户端会话 /// /// 客户端会话信息 /// private class ClientSession { /// /// 会话 ID /// public string SessionId { get; set; } /// /// TCP 客户端 /// public TcpClient TcpClient { get; set; } /// /// 网络流 /// public NetworkStream Stream { get; set; } /// /// 远程 IP 地址 /// public string RemoteIp { get; set; } /// /// 远程端口 /// public int RemotePort { get; set; } /// /// 连接时间 /// public DateTime ConnectedTime { get; set; } } #endregion } }