From 559890c482f5973f06aafdfec9550fee5ba3c7f2 Mon Sep 17 00:00:00 2001
From: wenxiangchao <wenxiangchao@ihengxin.com.cn>
Date: 星期一, 09 十一月 2026 17:02:15 +0800
Subject: [PATCH] feat: CAN 模拟器 TCP 化 + 多设备并发调试 + 后台生命周期管理

---
 CanSimulatorServer/CanSimulatorServer.Core/TcpSimulatorHost.cs |   92 ++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/CanSimulatorServer/CanSimulatorServer.Core/TcpSimulatorHost.cs b/CanSimulatorServer/CanSimulatorServer.Core/TcpSimulatorHost.cs
new file mode 100644
index 0000000..6d49a80
--- /dev/null
+++ b/CanSimulatorServer/CanSimulatorServer.Core/TcpSimulatorHost.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Concurrent;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+using log4net;
+
+namespace CanSimulatorServer
+{
+    /// <summary>
+    /// 妯℃嫙鍣� TCP 瀹夸富锛氱洃鍚鍙c�佹帴鍙楄繛鎺ャ�佷负姣忚繛鎺ュ缓绔嬩細璇濓紝骞舵寔鏈夋�荤嚎娉ㄥ唽琛ㄣ��
+    /// port=0 鏃剁敱绯荤粺鍒嗛厤涓存椂绔彛锛圥ort 灞炴�ц鍙栧疄闄呭�硷紝娴嬭瘯鍥炵幆鐢級銆�
+    /// UI 瀹夸富涓庢祴璇� fixture 鍏辩敤鏈被锛屼繚璇佹湇鍔$琛屼负鍗曚竴璺緞銆�
+    /// </summary>
+    public sealed class TcpSimulatorHost : IDisposable
+    {
+        private static readonly ILog Log = LogManager.GetLogger(typeof(TcpSimulatorHost));
+
+        private TcpListener? _listener;
+        private readonly ConcurrentDictionary<ServerSession, byte> _sessions = new();
+        private readonly CancellationTokenSource _cts = new();
+        private int _acceptedCount;
+
+        public CanBusManager Manager { get; } = new();
+
+        /// <summary>瀹為檯鐩戝惉绔彛锛圫tartAsync 鍚庢湁鏁堬級</summary>
+        public int Port { get; private set; }
+
+        public int ActiveSessionCount => _sessions.Count;
+        public int AcceptedCount => _acceptedCount;
+
+        /// <summary>鏂颁細璇濆缓绔嬩簨浠讹紙UI 鑺傜偣鏍戣闃咃級</summary>
+        public event Action<ServerSession>? SessionAttached;
+
+        public Task StartAsync(int port = 0, bool listenAll = false)
+        {
+            if (_listener != null) throw new InvalidOperationException("瀹夸富宸插湪杩愯");
+
+            var ip = listenAll ? IPAddress.Any : IPAddress.Loopback;
+            _listener = new TcpListener(ip, port);
+            _listener.Start();
+            Port = ((IPEndPoint)_listener.LocalEndpoint).Port;
+
+            Log.Info($"[SimServer] 鐩戝惉 {ip}:{Port}");
+            _ = Task.Run(() => AcceptLoopAsync(_cts.Token));
+            return Task.CompletedTask;
+        }
+
+        private async Task AcceptLoopAsync(CancellationToken ct)
+        {
+            while (!ct.IsCancellationRequested)
+            {
+                TcpClient? client = null;
+                try
+                {
+                    client = await _listener!.AcceptTcpClientAsync().ConfigureAwait(false);
+                    Interlocked.Increment(ref _acceptedCount);
+                    var session = new ServerSession(client, Manager, s => _sessions.TryRemove(s, out _));
+                    if (_sessions.TryAdd(session, 0))
+                    {
+                        SessionAttached?.Invoke(session);
+                        session.Start();
+                    }
+                    client = null;
+                }
+                catch (OperationCanceledException) { break; }
+                catch (SocketException) { break; } // listener 宸插仠姝�
+                catch (Exception ex)
+                {
+                    Log.Warn($"[SimServer] 鎺ュ彈杩炴帴澶辫触: {ex.Message}");
+                    client?.Close();
+                    try { await Task.Delay(200, ct).ConfigureAwait(false); }
+                    catch (OperationCanceledException) { break; }
+                }
+            }
+        }
+
+        public void Dispose()
+        {
+            try { _cts.Cancel(); } catch { }
+            try { _listener?.Stop(); } catch { }
+            foreach (var s in _sessions.Keys)
+            {
+                try { s.Dispose(); } catch { }
+            }
+            _sessions.Clear();
+            _cts.Dispose();
+            Log.Info("[SimServer] 瀹夸富宸插仠姝�");
+        }
+    }
+}

--
Gitblit v1.9.1