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