U:调整结构性目录

This commit is contained in:
jimmy committed 2025-06-18 09:19:25 +08:00
1 parent 693b390df0
commit c255419412
172 files changed
+839 -18898

No files matched your search

@@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Fleck" Version="1.2.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Fleck" Version="1.2.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,41 @@
using System.Text.Json;
namespace Application;
// 7. 示例消息处理器
public class ChatMessageHandler : IMessageHandler
{
public string MessageType => "chat";
public async Task<object?> HandleAsync(string connectionId, string data)
{
try
{
var chatData = JsonSerializer.Deserialize<ChatData>(data);
if (chatData == null) return new { status = "error", message = "无效的聊天数据" };
// 处理聊天逻辑
return new
{
status = "success",
message = "聊天消息已接收",
echo = new
{
from = connectionId,
content = chatData.Content,
timestamp = DateTime.UtcNow
}
};
}
catch (Exception ex)
{
return new { status = "error", message = ex.Message };
}
}
public class ChatData
{
public string Content { get; set; } = string.Empty;
}
}
@@ -0,0 +1,9 @@
namespace Application;
public class Class1
{
void main()
{
}
}
@@ -0,0 +1,47 @@
namespace Application;
// 4. 实现连接管理器
using System.Collections.Concurrent;
using System.Net.WebSockets;
public class ConnectionManager : IConnectionManager
{
private readonly ConcurrentDictionary<string, WebSocket> _connections = new();
public void AddConnection(string connectionId, WebSocket webSocket)
{
_connections.TryAdd(connectionId, webSocket);
}
public void RemoveConnection(string connectionId)
{
if (_connections.TryRemove(connectionId, out var webSocket))
{
if (webSocket.State == WebSocketState.Open)
{
_ = Task.Run(async () =>
{
try
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Connection removed", CancellationToken.None);
}
catch { /* 忽略关闭时的异常 */ }
});
}
}
}
public WebSocket? GetConnection(string connectionId)
{
_connections.TryGetValue(connectionId, out var webSocket);
return webSocket?.State == WebSocketState.Open ? webSocket : null;
}
public IEnumerable<string> GetAllConnectionIds()
{
return _connections.Where(c => c.Value.State == WebSocketState.Open).Select(c => c.Key);
}
public int Count => _connections.Count(c => c.Value.State == WebSocketState.Open);
}
@@ -0,0 +1,37 @@
using System.Net.WebSockets;
namespace Application;
// 1. 服务接口定义 - 便于单元测试和依赖注入
public interface IWebSocketServerService
{
event Action<string, string>? MessageReceived;
event Action<string>? ClientConnected;
event Action<string>? ClientDisconnected;
event Action<string>? ServerMessage;
Task<bool> StartAsync(string url);
Task StopAsync();
Task SendMessageAsync(string connectionId, object message);
Task BroadcastMessageAsync(object message);
bool IsRunning { get; }
int ConnectionCount { get; }
IEnumerable<string> GetConnectedClients();
}
// 2. 消息处理策略接口
public interface IMessageHandler
{
string MessageType { get; }
Task<object?> HandleAsync(string connectionId, string data);
}
// 3. 连接管理接口
public interface IConnectionManager
{
void AddConnection(string connectionId, WebSocket webSocket);
void RemoveConnection(string connectionId);
WebSocket? GetConnection(string connectionId);
IEnumerable<string> GetAllConnectionIds();
int Count { get; }
}
@@ -0,0 +1,11 @@
namespace Application;
// 5. 消息模型
public class WebSocketMessage
{
public string Type { get; set; } = string.Empty;
public string Data { get; set; } = string.Empty;
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
public string? ConnectionId { get; set; }
}
@@ -0,0 +1,276 @@
namespace Application;
// 6. 主要的WebSocket服务实现
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Text.Json;
public class WebSocketServerService : IWebSocketServerService, IDisposable
{
private readonly IConnectionManager _connectionManager;
private readonly Dictionary<string, IMessageHandler> _messageHandlers;
private HttpListener? _httpListener;
private CancellationTokenSource? _cancellationTokenSource;
private readonly SemaphoreSlim _startStopSemaphore = new(1, 1);
public event Action<string, string>? MessageReceived;
public event Action<string>? ClientConnected;
public event Action<string>? ClientDisconnected;
public event Action<string>? ServerMessage;
public bool IsRunning { get; private set; }
public int ConnectionCount => _connectionManager.Count;
public WebSocketServerService(IConnectionManager connectionManager)
{
_connectionManager = connectionManager;
_messageHandlers = new Dictionary<string, IMessageHandler>();
}
// 注册消息处理器
public void RegisterMessageHandler(IMessageHandler handler)
{
_messageHandlers[handler.MessageType.ToLower()] = handler;
}
public async Task<bool> StartAsync(string url)
{
await _startStopSemaphore.WaitAsync();
try
{
if (IsRunning) return true;
_httpListener = new HttpListener();
_httpListener.Prefixes.Add(url);
_cancellationTokenSource = new CancellationTokenSource();
try
{
_httpListener.Start();
IsRunning = true;
ServerMessage?.Invoke($"WebSocket服务器已启动: {url}");
// 开始监听连接
_ = Task.Run(() => ListenForConnectionsAsync(_cancellationTokenSource.Token));
return true;
}
catch (Exception ex)
{
ServerMessage?.Invoke($"启动服务器失败: {ex.Message}");
return false;
}
}
finally
{
_startStopSemaphore.Release();
}
}
public async Task StopAsync()
{
await _startStopSemaphore.WaitAsync();
try
{
if (!IsRunning) return;
_cancellationTokenSource?.Cancel();
_httpListener?.Stop();
_httpListener?.Close();
// 关闭所有连接
foreach (var connectionId in _connectionManager.GetAllConnectionIds().ToList())
{
_connectionManager.RemoveConnection(connectionId);
}
IsRunning = false;
ServerMessage?.Invoke("WebSocket服务器已停止");
}
finally
{
_startStopSemaphore.Release();
}
}
private async Task ListenForConnectionsAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested && _httpListener!.IsListening)
{
try
{
var context = await _httpListener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
// 不等待,让连接处理在后台进行
_ = Task.Run(() => ProcessWebSocketRequestAsync(context, cancellationToken), cancellationToken);
}
else
{
// 对非WebSocket请求返回404
context.Response.StatusCode = 404;
context.Response.Close();
}
}
catch (HttpListenerException) when (cancellationToken.IsCancellationRequested)
{
break;
}
catch (Exception ex)
{
ServerMessage?.Invoke($"监听连接时出错: {ex.Message}");
}
}
}
private async Task ProcessWebSocketRequestAsync(HttpListenerContext context, CancellationToken cancellationToken)
{
WebSocketContext? webSocketContext = null;
string connectionId = Guid.NewGuid().ToString();
try
{
webSocketContext = await context.AcceptWebSocketAsync(null);
var webSocket = webSocketContext.WebSocket;
_connectionManager.AddConnection(connectionId, webSocket);
ClientConnected?.Invoke(connectionId);
ServerMessage?.Invoke($"客户端连接: {connectionId}");
await HandleWebSocketConnectionAsync(webSocket, connectionId, cancellationToken);
}
catch (Exception ex)
{
ServerMessage?.Invoke($"处理WebSocket请求时出错 [{connectionId}]: {ex.Message}");
}
finally
{
_connectionManager.RemoveConnection(connectionId);
ClientDisconnected?.Invoke(connectionId);
ServerMessage?.Invoke($"客户端断开: {connectionId}");
}
}
private async Task HandleWebSocketConnectionAsync(WebSocket webSocket, string connectionId, CancellationToken cancellationToken)
{
var buffer = new byte[1024 * 4];
try
{
while (webSocket.State == WebSocketState.Open && !cancellationToken.IsCancellationRequested)
{
var result = await webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), cancellationToken);
if (result.MessageType == WebSocketMessageType.Text)
{
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
MessageReceived?.Invoke(connectionId, message);
// 处理消息但不等待响应,避免阻塞接收循环
_ = Task.Run(() => ProcessMessageAsync(message, connectionId), cancellationToken);
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", cancellationToken);
break;
}
}
}
catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
{
// 正常取消操作
}
catch (WebSocketException ex) when (ex.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
{
// 客户端异常断开连接
}
catch (Exception ex)
{
ServerMessage?.Invoke($"处理WebSocket连接时出错 [{connectionId}]: {ex.Message}");
}
}
private async Task ProcessMessageAsync(string message, string connectionId)
{
try
{
var messageObj = JsonSerializer.Deserialize<WebSocketMessage>(message);
if (messageObj == null) return;
messageObj.ConnectionId = connectionId;
messageObj.Timestamp = DateTime.UtcNow;
// 查找对应的消息处理器
if (_messageHandlers.TryGetValue(messageObj.Type.ToLower(), out var handler))
{
var response = await handler.HandleAsync(connectionId, messageObj.Data);
if (response != null)
{
await SendMessageAsync(connectionId, response);
}
}
else
{
var errorResponse = new { status = "error", message = $"未知消息类型: {messageObj.Type}" };
await SendMessageAsync(connectionId, errorResponse);
}
}
catch (JsonException)
{
var errorResponse = new { status = "error", message = "无效的JSON格式" };
await SendMessageAsync(connectionId, errorResponse);
}
catch (Exception ex)
{
ServerMessage?.Invoke($"处理消息时出错 [{connectionId}]: {ex.Message}");
}
}
public async Task SendMessageAsync(string connectionId, object message)
{
var webSocket = _connectionManager.GetConnection(connectionId);
if (webSocket != null)
{
try
{
var json = JsonSerializer.Serialize(message);
var buffer = Encoding.UTF8.GetBytes(json);
await webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
}
catch (Exception ex)
{
ServerMessage?.Invoke($"发送消息失败 [{connectionId}]: {ex.Message}");
}
}
}
public async Task BroadcastMessageAsync(object message)
{
var json = JsonSerializer.Serialize(message);
var tasks = new List<Task>();
foreach (var connectionId in _connectionManager.GetAllConnectionIds())
{
tasks.Add(SendMessageAsync(connectionId, message));
}
if (tasks.Count > 0)
{
await Task.WhenAll(tasks);
}
}
public IEnumerable<string> GetConnectedClients()
{
return _connectionManager.GetAllConnectionIds();
}
public void Dispose()
{
_ = Task.Run(async () => await StopAsync());
_startStopSemaphore?.Dispose();
_cancellationTokenSource?.Dispose();
}
}