using System.Net; using System.Net.Sockets; using System.Text; using System.Text.Json; using System.IO; using WIDESEAWCS_Core.LogHelper; namespace WIDESEAWCS_Tasks.SocketServer { public partial class TcpSocketServer { /// /// 异步启动 TCP Socket 服务器 /// /// /// 创建 TCP 监听器并开始接受客户端连接。 /// 如果服务器已在运行或被禁用,直接返回。 /// 启动后启动接受循环和客户端监控任务。 /// /// 取消令牌 /// 启动任务 public async Task StartAsync(CancellationToken cancellationToken) { if (IsRunning || !_options.Enabled) { return; } // 解析监听地址 IPAddress ipAddress = IPAddress.Any; if (IPAddress.TryParse(_options.IpAddress, out IPAddress? parsedAddress)) { ipAddress = parsedAddress; } await Task.Delay(5000); // 创建监听器 _listener = new TcpListener(ipAddress, _options.Port); _listener.Start(_options.Backlog); _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); IsRunning = true; // 启动接受客户端连接循环 _ = AcceptLoopAsync(_cts.Token); // 启动客户端监控任务(检查空闲超时) _monitorTask = Task.Run(() => MonitorClientsAsync(_cts.Token)); return; } /// /// 异步停止 TCP Socket 服务器 /// /// /// 停止接受新连接,等待所有客户端任务完成。 /// /// 取消令牌 /// 停止任务 public async Task StopAsync(CancellationToken cancellationToken) { if (!IsRunning) { return; } // 发送取消信号 _cts?.Cancel(); // 停止监听 _listener?.Stop(); // 等待所有客户端任务完成 Task[] tasks; lock (_syncRoot) { tasks = _clientTasks.ToArray(); } if (tasks.Length > 0) { await Task.WhenAll(tasks); } IsRunning = false; } /// /// 异步接受客户端连接的主循环 /// /// /// 异步接受客户端连接的主循环 /// /// /// 在后台线程中持续接受新的客户端连接。 /// 当有新连接时,将其添加到客户端字典并启动消息处理任务。 /// /// 取消令牌 private async Task AcceptLoopAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { TcpClient? client = null; try { // 等待客户端连接 client = await _listener!.AcceptTcpClientAsync().WaitAsync(cancellationToken); QuartzLogger.Info($"客户端连接:{client.Client.RemoteEndPoint.ToString()}"); } catch (OperationCanceledException) { break; } catch (ObjectDisposedException) { break; } catch { if (cancellationToken.IsCancellationRequested) break; } if (client == null) continue; // 生成客户端 ID(使用远程端点地址) string clientId = GetClientId(client); // 添加到客户端字典 lock (_syncRoot) { _clients[clientId] = client; _clientLocks[clientId] = new SemaphoreSlim(1, 1); } } } /// /// 移除客户端连接 /// /// /// 关闭客户端连接并清理相关资源: /// - 关闭 TcpClient /// - 释放信号量 /// - 移除活跃时间和编码记录 /// - 移除设备绑定 /// /// 要移除的客户端唯一标识 private void RemoveClient(string clientId) { lock (_syncRoot) { // 关闭并移除客户端连接 if (_clients.TryGetValue(clientId, out var client)) { try { client.Close(); } catch { } _clients.Remove(clientId); } // 释放信号量 if (_clientLocks.TryGetValue(clientId, out var sem)) { _clientLocks.Remove(clientId); sem.Dispose(); } // 移除活跃时间记录 _clientLastActive.Remove(clientId); // 移除编码记录 _clientEncodings.Remove(clientId); // 移除设备绑定 var deviceIds = _deviceBindings.Where(kv => kv.Value == clientId).Select(kv => kv.Key).ToList(); foreach (var deviceId in deviceIds) { _deviceBindings.Remove(deviceId); } } } /// /// 异步监控客户端空闲超时 /// /// /// 定期检查所有客户端的最后活跃时间, /// 如果超过空闲超时时间,断开该客户端连接。 /// /// 取消令牌 private async Task MonitorClientsAsync(CancellationToken cancellationToken) { while (!cancellationToken.IsCancellationRequested) { try { List toRemove = new(); lock (_syncRoot) { foreach (var kv in _clientLastActive) { // 检查是否超过空闲超时 if (_options.IdleTimeoutSeconds > 0 && DateTime.Now - kv.Value > TimeSpan.FromSeconds(_options.IdleTimeoutSeconds)) { toRemove.Add(kv.Key); } } } // 断开超时的客户端 foreach (var cid in toRemove) { RemoveClient(cid); Log($"[{DateTime.Now}] TcpSocketServer disconnect idle client {cid}"); } } catch { } // 每秒检查一次 try { await Task.Delay(1000, cancellationToken); } catch { } } } /// /// 获取客户端唯一标识 /// /// /// 使用客户端的远程端点地址作为标识。 /// 如果远程端点不可用,生成随机 GUID。 /// /// TCP 客户端 /// 客户端标识字符串 public static string GetClientId(TcpClient client) { return client.Client.RemoteEndPoint?.ToString() ?? Guid.NewGuid().ToString(); } } }