磁导航1.0内部交管和信号交互

This commit is contained in:
ykkokluo
2026-08-24 14:55:35 +08:00
parent cacc5fea5c
commit 244b0af6c8
60 changed files with 6395 additions and 294 deletions
@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace StandardScene.MagCarSimulator
{
public sealed class MagCarSimTcpServer : IDisposable
{
private readonly IPAddress _address;
private readonly int _port;
private readonly Func<byte[], byte[]> _handler;
private readonly object _clientsLock = new object();
private readonly HashSet<TcpClient> _clients = new HashSet<TcpClient>();
private TcpListener _listener;
private CancellationTokenSource _cts;
private int _clientCount;
private bool _running;
public MagCarSimTcpServer(IPAddress address, int port, Func<byte[], byte[]> handler)
{
_address = address ?? IPAddress.Any;
_port = port;
_handler = handler ?? throw new ArgumentNullException(nameof(handler));
}
public bool IsRunning => _running;
public int ClientCount => Volatile.Read(ref _clientCount);
public void Start()
{
if (_running)
{
return;
}
_cts = new CancellationTokenSource();
_listener = new TcpListener(_address, _port);
_listener.Server.NoDelay = true;
_listener.Start();
_running = true;
_ = Task.Run(() => AcceptLoop(_cts.Token));
}
public void Dispose()
{
_running = false;
try
{
_cts?.Cancel();
}
catch
{
}
try
{
_listener?.Stop();
}
catch
{
}
List<TcpClient> clients;
lock (_clientsLock)
{
clients = new List<TcpClient>(_clients);
_clients.Clear();
}
foreach (var client in clients)
{
try
{
client.Close();
}
catch
{
}
}
_cts?.Dispose();
_cts = null;
_listener = null;
}
private async Task AcceptLoop(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
TcpClient client;
try
{
client = await _listener.AcceptTcpClientAsync(token).ConfigureAwait(false);
}
catch (OperationCanceledException)
{
return;
}
catch (ObjectDisposedException)
{
return;
}
catch (SocketException)
{
if (token.IsCancellationRequested)
{
return;
}
continue;
}
lock (_clientsLock)
{
_clients.Add(client);
}
_ = Task.Run(() => HandleClient(client, token), token);
}
}
private void HandleClient(TcpClient client, CancellationToken token)
{
Interlocked.Increment(ref _clientCount);
try
{
client.NoDelay = true;
client.ReceiveTimeout = 0;
using (var stream = client.GetStream())
{
var buffer = new byte[MagCarSimProtocol.FrameLength];
while (!token.IsCancellationRequested)
{
if (!ReadExact(stream, buffer, token))
{
return;
}
byte[] response;
try
{
response = _handler(buffer);
}
catch (Exception ex)
{
MagCarSimLog.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] TCP 处理异常: {ex.Message}");
return;
}
if (response == null || response.Length != MagCarSimProtocol.FrameLength)
{
continue;
}
stream.Write(response, 0, response.Length);
stream.Flush();
}
}
}
catch (Exception ex) when (IsBenign(ex))
{
}
catch (Exception ex)
{
MagCarSimLog.WriteLine($"[{DateTime.Now:HH:mm:ss.fff}] TCP 连接异常: {ex.Message}");
}
finally
{
lock (_clientsLock)
{
_clients.Remove(client);
}
try
{
client.Dispose();
}
catch
{
}
Interlocked.Decrement(ref _clientCount);
}
}
private static bool ReadExact(NetworkStream stream, byte[] buffer, CancellationToken token)
{
var offset = 0;
while (offset < buffer.Length)
{
token.ThrowIfCancellationRequested();
int read;
try
{
read = stream.Read(buffer, offset, buffer.Length - offset);
}
catch (Exception ex) when (IsBenign(ex))
{
return false;
}
if (read == 0)
{
return false;
}
offset += read;
}
return true;
}
private static bool IsBenign(Exception ex)
{
for (var current = ex; current != null; current = current.InnerException)
{
if (current is ObjectDisposedException || current is OperationCanceledException)
{
return true;
}
if (current is SocketException socketEx)
{
switch (socketEx.SocketErrorCode)
{
case SocketError.OperationAborted:
case SocketError.Interrupted:
case SocketError.ConnectionAborted:
case SocketError.ConnectionReset:
case SocketError.Shutdown:
return true;
}
}
}
return false;
}
}
}