A:增加 http 端口监听;增加http参数解析;增加websocket的客户端uuid识别和存储
This commit is contained in:
1 parent
1b35e2dfd7
commit
f2dc4441d4
16 files changed
+611
-121
No files matched your search
@@ -0,0 +1,359 @@
|
|||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Web;
|
||||||
|
using Fleck;
|
||||||
|
|
||||||
|
namespace Common.Net.HttpConn;
|
||||||
|
|
||||||
|
// HTTP 方法枚举
|
||||||
|
public enum HttpMethod
|
||||||
|
{
|
||||||
|
GET,
|
||||||
|
POST,
|
||||||
|
PUT,
|
||||||
|
DELETE,
|
||||||
|
PATCH,
|
||||||
|
HEAD,
|
||||||
|
OPTIONS
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由处理委托
|
||||||
|
public delegate Task RequestHandler(HttpContext context);
|
||||||
|
|
||||||
|
// 中间件委托
|
||||||
|
public delegate Task<bool> MiddlewareHandler(HttpContext context);
|
||||||
|
|
||||||
|
// HTTP 上下文
|
||||||
|
public class HttpContext
|
||||||
|
{
|
||||||
|
public HttpListenerRequest Request { get; set; }
|
||||||
|
public HttpListenerResponse Response { get; set; }
|
||||||
|
public Dictionary<string, object> Items { get; set; } = new Dictionary<string, object>();
|
||||||
|
public Dictionary<string, string> RouteParams { get; set; } = new Dictionary<string, string>();
|
||||||
|
public NameValueCollection QueryParams { get; set; }
|
||||||
|
public string RequestBody { get; set; }
|
||||||
|
public T GetRequestBody<T>() => JsonSerializer.Deserialize<T>(RequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 路由信息
|
||||||
|
public class Route
|
||||||
|
{
|
||||||
|
public string Pattern { get; set; }
|
||||||
|
public HttpMethod Method { get; set; }
|
||||||
|
public RequestHandler Handler { get; set; }
|
||||||
|
public List<string> ParamNames { get; set; } = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HTTP 服务器主类
|
||||||
|
/// </summary>
|
||||||
|
public class HttpServer
|
||||||
|
{
|
||||||
|
private readonly HttpListener _listener;
|
||||||
|
private readonly List<Route> _routes = new List<Route>();
|
||||||
|
private readonly List<MiddlewareHandler> _middlewares = new List<MiddlewareHandler>();
|
||||||
|
private readonly string _prefix;
|
||||||
|
private bool _isRunning;
|
||||||
|
private readonly SemaphoreSlim _concurrencySemaphore;
|
||||||
|
|
||||||
|
public HttpServer(string prefix = "http://localhost:8080/", int maxConcurrentRequests = 100)
|
||||||
|
{
|
||||||
|
_prefix = prefix.EndsWith("/") ? prefix : prefix + "/";
|
||||||
|
_listener = new HttpListener();
|
||||||
|
_listener.Prefixes.Add(_prefix);
|
||||||
|
_concurrencySemaphore = new SemaphoreSlim(maxConcurrentRequests, maxConcurrentRequests);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加中间件
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="middleware"></param>
|
||||||
|
public void UseMiddleware(MiddlewareHandler middleware)
|
||||||
|
{
|
||||||
|
_middlewares.Add(middleware);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 添加路由
|
||||||
|
/// </summary>
|
||||||
|
public void AddRoute(HttpMethod method, string pattern, RequestHandler handler)
|
||||||
|
{
|
||||||
|
var route = new Route
|
||||||
|
{
|
||||||
|
Method = method,
|
||||||
|
Pattern = pattern,
|
||||||
|
Handler = handler
|
||||||
|
};
|
||||||
|
|
||||||
|
// 解析路由参数
|
||||||
|
var parts = pattern.Split('/');
|
||||||
|
for (int i = 0; i < parts.Length; i++)
|
||||||
|
{
|
||||||
|
if (parts[i].StartsWith("{") && parts[i].EndsWith("}"))
|
||||||
|
{
|
||||||
|
route.ParamNames.Add(parts[i].Trim('{', '}'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_routes.Add(route);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 便捷路由方法
|
||||||
|
/// </summary>
|
||||||
|
public void Get(string pattern, RequestHandler handler) => AddRoute(HttpMethod.GET, pattern, handler);
|
||||||
|
public void Post(string pattern, RequestHandler handler) => AddRoute(HttpMethod.POST, pattern, handler);
|
||||||
|
public void Put(string pattern, RequestHandler handler) => AddRoute(HttpMethod.PUT, pattern, handler);
|
||||||
|
public void Delete(string pattern, RequestHandler handler) => AddRoute(HttpMethod.DELETE, pattern, handler);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 启动服务器
|
||||||
|
/// </summary>
|
||||||
|
public async Task StartAsync(CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
_listener.Start();
|
||||||
|
_isRunning = true;
|
||||||
|
Console.WriteLine($"HTTP Server started at {_prefix}");
|
||||||
|
|
||||||
|
while (_isRunning && !cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var listenerContext = await _listener.GetContextAsync().ConfigureAwait(false);
|
||||||
|
_ = Task.Run(async () => await HandleRequestAsync(listenerContext), cancellationToken);
|
||||||
|
}
|
||||||
|
catch (HttpListenerException ex) when (ex.ErrorCode == 995) // Listener stopped
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error accepting request: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 停止服务器
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
_isRunning = false;
|
||||||
|
_listener.Stop();
|
||||||
|
_listener.Close();
|
||||||
|
Console.WriteLine("HTTP Server stopped");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理请求
|
||||||
|
private async Task HandleRequestAsync(HttpListenerContext listenerContext)
|
||||||
|
{
|
||||||
|
await _concurrencySemaphore.WaitAsync();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var context = await CreateHttpContext(listenerContext);
|
||||||
|
|
||||||
|
// 执行中间件
|
||||||
|
foreach (var middleware in _middlewares)
|
||||||
|
{
|
||||||
|
if (!await middleware(context))
|
||||||
|
{
|
||||||
|
return; // 中间件返回 false,停止处理
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配路由并执行处理器
|
||||||
|
var route = MatchRoute(context);
|
||||||
|
if (route != null)
|
||||||
|
{
|
||||||
|
await route.Handler(context);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await SendNotFound(context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Request handling error: {ex}");
|
||||||
|
await SendInternalServerError(listenerContext.Response, ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
listenerContext.Response.Close();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
_concurrencySemaphore.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建 HTTP 上下文
|
||||||
|
private async Task<HttpContext> CreateHttpContext(HttpListenerContext listenerContext)
|
||||||
|
{
|
||||||
|
var context = new HttpContext
|
||||||
|
{
|
||||||
|
Request = listenerContext.Request,
|
||||||
|
Response = listenerContext.Response,
|
||||||
|
QueryParams = listenerContext.Request.QueryString
|
||||||
|
};
|
||||||
|
|
||||||
|
// 读取请求体
|
||||||
|
if (listenerContext.Request.HasEntityBody)
|
||||||
|
{
|
||||||
|
using (var reader = new StreamReader(listenerContext.Request.InputStream,
|
||||||
|
listenerContext.Request.ContentEncoding))
|
||||||
|
{
|
||||||
|
context.RequestBody = await reader.ReadToEndAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return context;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 匹配路由
|
||||||
|
private Route MatchRoute(HttpContext context)
|
||||||
|
{
|
||||||
|
var method = Enum.Parse<HttpMethod>(context.Request.HttpMethod);
|
||||||
|
var path = context.Request.Url.AbsolutePath;
|
||||||
|
|
||||||
|
foreach (var route in _routes.Where(r => r.Method == method))
|
||||||
|
{
|
||||||
|
if (TryMatchRoute(route, path, out var routeParams))
|
||||||
|
{
|
||||||
|
context.RouteParams = routeParams;
|
||||||
|
return route;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试匹配路由模式
|
||||||
|
private bool TryMatchRoute(Route route, string path, out Dictionary<string, string> routeParams)
|
||||||
|
{
|
||||||
|
routeParams = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
var routeParts = route.Pattern.Split('/');
|
||||||
|
var pathParts = path.Split('/');
|
||||||
|
|
||||||
|
if (routeParts.Length != pathParts.Length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (int i = 0; i < routeParts.Length; i++)
|
||||||
|
{
|
||||||
|
if (routeParts[i].StartsWith("{") && routeParts[i].EndsWith("}"))
|
||||||
|
{
|
||||||
|
var paramName = routeParts[i].Trim('{', '}');
|
||||||
|
routeParams[paramName] = HttpUtility.UrlDecode(pathParts[i]);
|
||||||
|
}
|
||||||
|
else if (routeParts[i] != pathParts[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送 404 响应
|
||||||
|
private async Task SendNotFound(HttpContext context)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 404;
|
||||||
|
await context.Response.WriteJsonAsync(new { error = "Not Found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送 500 响应
|
||||||
|
private async Task SendInternalServerError(HttpListenerResponse response, Exception ex)
|
||||||
|
{
|
||||||
|
response.StatusCode = 500;
|
||||||
|
await response.WriteJsonAsync(new { error = "Internal Server Error", message = ex.Message });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 响应扩展方法
|
||||||
|
public static class HttpListenerResponseExtensions
|
||||||
|
{
|
||||||
|
public static async Task WriteJsonAsync<T>(this HttpListenerResponse response, T data)
|
||||||
|
{
|
||||||
|
response.ContentType = "application/json; charset=utf-8";
|
||||||
|
var json = JsonSerializer.Serialize(data, new JsonSerializerOptions
|
||||||
|
{
|
||||||
|
WriteIndented = true,
|
||||||
|
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
|
||||||
|
});
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(json);
|
||||||
|
response.ContentLength64 = buffer.Length;
|
||||||
|
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task WriteTextAsync(this HttpListenerResponse response, string text)
|
||||||
|
{
|
||||||
|
response.ContentType = "text/plain; charset=utf-8";
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(text);
|
||||||
|
response.ContentLength64 = buffer.Length;
|
||||||
|
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task WriteHtmlAsync(this HttpListenerResponse response, string html)
|
||||||
|
{
|
||||||
|
response.ContentType = "text/html; charset=utf-8";
|
||||||
|
var buffer = Encoding.UTF8.GetBytes(html);
|
||||||
|
response.ContentLength64 = buffer.Length;
|
||||||
|
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 常用中间件
|
||||||
|
public static class Middlewares
|
||||||
|
{
|
||||||
|
// CORS 中间件
|
||||||
|
public static async Task<bool> Cors(HttpContext context)
|
||||||
|
{
|
||||||
|
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
|
||||||
|
context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
||||||
|
context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Authorization");
|
||||||
|
|
||||||
|
if (context.Request.HttpMethod == "OPTIONS")
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 204;
|
||||||
|
return false; // 停止后续处理
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 请求日志中间件
|
||||||
|
public static async Task<bool> RequestLogging(HttpContext context)
|
||||||
|
{
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
|
Console.WriteLine($"[{startTime:yyyy-MM-dd HH:mm:ss}] {context.Request.HttpMethod} {context.Request.Url}");
|
||||||
|
|
||||||
|
// 继续处理
|
||||||
|
return await Task.FromResult(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 认证中间件示例
|
||||||
|
public static async Task<bool> Authentication(HttpContext context)
|
||||||
|
{
|
||||||
|
var authHeader = context.Request.Headers["Authorization"];
|
||||||
|
if (string.IsNullOrEmpty(authHeader))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 401;
|
||||||
|
await context.Response.WriteJsonAsync(new { error = "Unauthorized" });
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 验证 token
|
||||||
|
// if (!ValidateToken(authHeader)) { ... }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
namespace Common.Net.Models;
|
||||||
|
|
||||||
|
public class ResponseModel<T>
|
||||||
|
{
|
||||||
|
public bool Success { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
public T? Data { get; set; }
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net.WebSockets;
|
using System.Net.WebSockets;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Web;
|
||||||
using Common.Logger;
|
using Common.Logger;
|
||||||
using Fleck;
|
using Fleck;
|
||||||
|
|
||||||
@@ -13,7 +14,17 @@ public class WebSocketManager
|
|||||||
public static WebSocketManager Instance => _instance.Value;
|
public static WebSocketManager Instance => _instance.Value;
|
||||||
|
|
||||||
private WebSocketServer _server;
|
private WebSocketServer _server;
|
||||||
private readonly ConcurrentDictionary<Guid, IWebSocketConnection> _connections;
|
|
||||||
|
/// <summary>
|
||||||
|
/// 所有建立客户端连接
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<Guid, ClientConnection> _connections;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 客户端私有 ID 与 socket id 对应表
|
||||||
|
/// </summary>
|
||||||
|
private readonly ConcurrentDictionary<string, Guid> _uuidToSocketId = new();
|
||||||
|
|
||||||
private readonly object _lockObject = new();
|
private readonly object _lockObject = new();
|
||||||
private bool _isStarted;
|
private bool _isStarted;
|
||||||
|
|
||||||
@@ -22,7 +33,7 @@ public class WebSocketManager
|
|||||||
|
|
||||||
private WebSocketManager()
|
private WebSocketManager()
|
||||||
{
|
{
|
||||||
_connections = new ConcurrentDictionary<Guid, IWebSocketConnection>();
|
_connections = new ConcurrentDictionary<Guid, ClientConnection>();
|
||||||
_messageHandlers = new ConcurrentDictionary<string, Func<CommandMessage, IWebSocketConnection, Task>>();
|
_messageHandlers = new ConcurrentDictionary<string, Func<CommandMessage, IWebSocketConnection, Task>>();
|
||||||
RegisterDefaultHandlers();
|
RegisterDefaultHandlers();
|
||||||
}
|
}
|
||||||
@@ -57,37 +68,93 @@ public class WebSocketManager
|
|||||||
_server?.Dispose();
|
_server?.Dispose();
|
||||||
CloseAllSocketsAsync();
|
CloseAllSocketsAsync();
|
||||||
_connections.Clear();
|
_connections.Clear();
|
||||||
|
_uuidToSocketId.Clear();
|
||||||
_isStarted = false;
|
_isStarted = false;
|
||||||
Log.Information("WebSocket服务器已停止");
|
Log.Information("WebSocket服务器已停止");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task CloseAllSocketsAsync()
|
public async Task CloseAllSocketsAsync()
|
||||||
{
|
{
|
||||||
foreach (var webSocketConnection in _connections)
|
foreach (var webSocketConnection in _connections)
|
||||||
{
|
{
|
||||||
webSocketConnection.Value.Close();
|
var socketConnection = webSocketConnection.Value.Socket;
|
||||||
|
socketConnection.Close();
|
||||||
|
var valueUuid = webSocketConnection.Value.Uuid;
|
||||||
|
_uuidToSocketId.TryRemove(valueUuid, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 连接建立
|
|
||||||
|
/// <summary>
|
||||||
|
/// 连接建立
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="socket"></param>
|
||||||
private void OnConnectionOpen(IWebSocketConnection socket)
|
private void OnConnectionOpen(IWebSocketConnection socket)
|
||||||
{
|
{
|
||||||
_connections.TryAdd(socket.ConnectionInfo.Id, socket);
|
// 从Path中解析查询参数
|
||||||
Log.Information($"客户端连接: {socket.ConnectionInfo.Id}");
|
var path = socket.ConnectionInfo.Path;
|
||||||
|
var userId = ExtractUserIdFromPath(path, "uuid");
|
||||||
|
|
||||||
// 发送欢迎消息
|
if (!string.IsNullOrEmpty(userId))
|
||||||
_ = SendToClient(socket.ConnectionInfo.Id, new ResponseMessage
|
|
||||||
{
|
{
|
||||||
Type = "welcome",
|
var conn = new ClientConnection
|
||||||
Success = true,
|
{
|
||||||
Message = "连接成功",
|
SocketId = socket.ConnectionInfo.Id,
|
||||||
Data = new { ClientId = socket.ConnectionInfo.Id }
|
Uuid = userId,
|
||||||
});
|
Socket = socket
|
||||||
|
};
|
||||||
|
_connections.TryAdd(socket.ConnectionInfo.Id, conn);
|
||||||
|
Log.Info($"客户端连接: {socket.ConnectionInfo.Id}, 私有 id : {userId}");
|
||||||
|
_uuidToSocketId.TryAdd(userId, socket.ConnectionInfo.Id);
|
||||||
|
|
||||||
|
// 发送欢迎消息
|
||||||
|
_ = SendToClient(socket.ConnectionInfo.Id, new ResponseMessage
|
||||||
|
{
|
||||||
|
Type = "welcome",
|
||||||
|
Success = true,
|
||||||
|
Message = "连接成功",
|
||||||
|
Data = new { ClientId = socket.ConnectionInfo.Id }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("连接缺少userId参数");
|
||||||
|
socket.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 解析参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">要解析的路径</param>
|
||||||
|
/// <param name="key">想要获取的目标 value </param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private string? ExtractUserIdFromPath(string path, string key)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 解析类似 "/?userId=123456" 的路径
|
||||||
|
if (path.Contains("?"))
|
||||||
|
{
|
||||||
|
var queryString = path.Split('?')[1];
|
||||||
|
var queryParams = HttpUtility.ParseQueryString(queryString);
|
||||||
|
return queryParams[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"解析userId时出错: {ex.Message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 连接关闭
|
// 连接关闭
|
||||||
private void OnConnectionClose(IWebSocketConnection socket)
|
private void OnConnectionClose(IWebSocketConnection socket)
|
||||||
{
|
{
|
||||||
_connections.TryRemove(socket.ConnectionInfo.Id, out _);
|
_connections.TryRemove(socket.ConnectionInfo.Id, out var conn);
|
||||||
|
if (conn?.Uuid != null)
|
||||||
|
_uuidToSocketId.TryRemove(conn.Uuid, out _);
|
||||||
Log.Information($"客户端断开: {socket.ConnectionInfo.Id}");
|
Log.Information($"客户端断开: {socket.ConnectionInfo.Id}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,59 +199,6 @@ public class WebSocketManager
|
|||||||
// 注册默认处理器
|
// 注册默认处理器
|
||||||
private void RegisterDefaultHandlers()
|
private void RegisterDefaultHandlers()
|
||||||
{
|
{
|
||||||
// 获取网络状态
|
|
||||||
RegisterHandler("getNetworkStatus", async (cmd, socket) =>
|
|
||||||
{
|
|
||||||
// cmd.Command;
|
|
||||||
// 这里应该调用你的网络状态获取逻辑
|
|
||||||
var networkStatus = GetNetworkStatus();
|
|
||||||
await SendToClient(socket.ConnectionInfo.Id, new ResponseMessage
|
|
||||||
{
|
|
||||||
Type = "networkStatus",
|
|
||||||
Success = true,
|
|
||||||
Data = networkStatus
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 获取防火墙规则
|
|
||||||
RegisterHandler("getFirewallRules", async (cmd, socket) =>
|
|
||||||
{
|
|
||||||
var firewallRules = GetFirewallRules();
|
|
||||||
await SendToClient(socket.ConnectionInfo.Id, new ResponseMessage
|
|
||||||
{
|
|
||||||
Type = "firewallRules",
|
|
||||||
Success = true,
|
|
||||||
Data = firewallRules
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 添加防火墙规则
|
|
||||||
RegisterHandler("addFirewallRule", async (cmd, socket) =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var ruleData = JsonSerializer.Deserialize<FirewallRuleMessage>(cmd.Data.ToString());
|
|
||||||
var success = AddFirewallRule(ruleData);
|
|
||||||
|
|
||||||
await SendToClient(socket.ConnectionInfo.Id, new ResponseMessage
|
|
||||||
{
|
|
||||||
Type = "addFirewallRuleResponse",
|
|
||||||
Success = success,
|
|
||||||
Message = success ? "规则添加成功" : "规则添加失败"
|
|
||||||
});
|
|
||||||
|
|
||||||
// 广播更新给所有客户端
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
await BroadcastFirewallUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await SendErrorResponse(socket, $"添加规则失败: {ex.Message}");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 心跳检测
|
// 心跳检测
|
||||||
RegisterHandler("ping", async (cmd, socket) =>
|
RegisterHandler("ping", async (cmd, socket) =>
|
||||||
{
|
{
|
||||||
@@ -197,7 +211,9 @@ public class WebSocketManager
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送消息给指定客户端
|
/// <summary>
|
||||||
|
/// 发送消息给指定客户端
|
||||||
|
/// </summary>
|
||||||
public async Task<bool> SendToClient(Guid clientId, ResponseMessage message)
|
public async Task<bool> SendToClient(Guid clientId, ResponseMessage message)
|
||||||
{
|
{
|
||||||
if (_connections.TryGetValue(clientId, out var socket))
|
if (_connections.TryGetValue(clientId, out var socket))
|
||||||
@@ -205,7 +221,7 @@ public class WebSocketManager
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var json = JsonSerializer.Serialize(message);
|
var json = JsonSerializer.Serialize(message);
|
||||||
await socket.Send(json);
|
await socket.Socket.Send(json);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -218,7 +234,28 @@ public class WebSocketManager
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 广播消息给所有客户端
|
/// <summary>
|
||||||
|
/// 发送消息给指定客户端
|
||||||
|
/// </summary>
|
||||||
|
public async Task<bool> SendToClient(string uuid, ResponseMessage message)
|
||||||
|
{
|
||||||
|
var tryGetValue = _uuidToSocketId.TryGetValue(uuid, out var socketId);
|
||||||
|
var ans = false;
|
||||||
|
if (tryGetValue)
|
||||||
|
{
|
||||||
|
ans = await SendToClient(socketId, message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log.Error4Ctx("无法获取有效客户端 uuid !");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 广播消息给所有客户端
|
||||||
|
/// </summary>
|
||||||
public async Task BroadcastMessage(ResponseMessage message)
|
public async Task BroadcastMessage(ResponseMessage message)
|
||||||
{
|
{
|
||||||
var json = JsonSerializer.Serialize(message);
|
var json = JsonSerializer.Serialize(message);
|
||||||
@@ -226,7 +263,7 @@ public class WebSocketManager
|
|||||||
|
|
||||||
foreach (var connection in _connections.Values)
|
foreach (var connection in _connections.Values)
|
||||||
{
|
{
|
||||||
tasks.Add(connection.Send(json));
|
tasks.Add(connection.Socket.Send(json));
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -312,3 +349,10 @@ public class WebSocketManager
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ClientConnection
|
||||||
|
{
|
||||||
|
public Guid SocketId { get; init; }
|
||||||
|
public string Uuid { get; init; }
|
||||||
|
public IWebSocketConnection Socket { get; init; }
|
||||||
|
}
|
||||||
@@ -398,6 +398,13 @@ public static class Log
|
|||||||
var str = GetLog(callerMemberName, Path.GetFileName(filePath), callerLineNumber, message);
|
var str = GetLog(callerMemberName, Path.GetFileName(filePath), callerLineNumber, message);
|
||||||
Debug(str);
|
Debug(str);
|
||||||
}
|
}
|
||||||
|
public static void Info(string message, params object[] args) => Information(message, args);
|
||||||
|
|
||||||
|
public static void Info4Ctx(string message, [CallerMemberName] string callerMemberName = "",
|
||||||
|
[CallerFilePath] string filePath = "", [CallerLineNumber] int callerLineNumber = 0)
|
||||||
|
{
|
||||||
|
Information4Ctx(message,callerMemberName,filePath,callerLineNumber);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Information(string message, params object[] args) => Instance.LogInformation(message, args);
|
public static void Information(string message, params object[] args) => Instance.LogInformation(message, args);
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ public static class SysHelper
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static int GetAvailablePort()
|
public static int GetAvailablePort()
|
||||||
{
|
{
|
||||||
|
// todo: 2025/6/24 15:53 开发过程中使用固定端口
|
||||||
|
return 8267;
|
||||||
|
|
||||||
TcpListener listener = new TcpListener(IPAddress.Loopback, 0); // 端口号为0表示由系统自动分配
|
TcpListener listener = new TcpListener(IPAddress.Loopback, 0); // 端口号为0表示由系统自动分配
|
||||||
listener.Start();
|
listener.Start();
|
||||||
int port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
int port = ((IPEndPoint)listener.LocalEndpoint).Port;
|
||||||
|
|||||||
@@ -14,8 +14,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Common\Common.csproj" />
|
<ProjectReference Include="..\Common\Common.csproj" />
|
||||||
<ProjectReference Include="..\Utils.ETW\Utils.ETW.csproj" />
|
|
||||||
<ProjectReference Include="..\WinDivertNet\WinDivertNet.csproj" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using Utils.ETW.Models;
|
|
||||||
|
|
||||||
namespace Infrastructure.Models;
|
namespace Infrastructure.Models;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACancellationToken_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F2565b9d99fdde488bc7801b84387b2cc864959cfb63212e1ff576fc9c6bb7e_003FCancellationToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACancellationToken_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F2565b9d99fdde488bc7801b84387b2cc864959cfb63212e1ff576fc9c6bb7e_003FCancellationToken_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChannel_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6c1b38ac9eb24f67b802360dcd86fc07208b0_003F10_003F645700ec_003FChannel_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AChannel_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6c1b38ac9eb24f67b802360dcd86fc07208b0_003F10_003F645700ec_003FChannel_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AConcurrentDictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4c583240ebf1454eb7477e1b97ab637b43928_003F90_003F523b730a_003FConcurrentDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AConcurrentDictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4c583240ebf1454eb7477e1b97ab637b43928_003F90_003F523b730a_003FConcurrentDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AConcurrentDictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fd553f324e2344c688409eee4ccb3e03643938_003F99_003F85a9e1f8_003FConcurrentDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultInterpolatedStringHandler_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fe4_003Fdb4307f5_003FDefaultInterpolatedStringHandler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADefaultInterpolatedStringHandler_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fe4_003Fdb4307f5_003FDefaultInterpolatedStringHandler_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F38_003Faa4e6832_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADictionary_00602_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F38_003Faa4e6832_003FDictionary_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcca5cfb955e146648d91eb22ffe4627a84930_003Fae_003Fc940e3b4_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AEnumerable_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fcca5cfb955e146648d91eb22ffe4627a84930_003Fae_003Fc940e3b4_003FEnumerable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@@ -14,10 +15,13 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileVersionInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7fad91e527c1434bb313ddbc78144605b8a0_003F3f_003F911bc64d_003FFileVersionInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFileVersionInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F7fad91e527c1434bb313ddbc78144605b8a0_003F3f_003F911bc64d_003FFileVersionInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F71_003F40854420_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFile_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F71_003F40854420_003FFile_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFuture_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F6f90c6c13479b8c2a5be98f3d75dfc3bd885a055652d8a32904ca2448132949e_003FFuture_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AFuture_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F6f90c6c13479b8c2a5be98f3d75dfc3bd885a055652d8a32904ca2448132949e_003FFuture_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpListener_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F28febf18c0c64165a91fffc7144abdc786908_003F39_003Fa4eb9e55_003FHttpListener_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIcon_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F946b37ae1f1648b7a334a81e4b6ce11c64330_003F21_003F67e31def_003FIcon_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIcon_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F946b37ae1f1648b7a334a81e4b6ce11c64330_003F21_003F67e31def_003FIcon_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIDisposable_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5aeb6167299d4cfba30c86624130edbcc90938_003F41_003F0f283a8f_003FIDisposable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIDisposable_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5aeb6167299d4cfba30c86624130edbcc90938_003F41_003F0f283a8f_003FIDisposable_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIPAddress_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5dc54dc133694e6ca1812e5e56e958df388a0_003F68_003F0bc1a452_003FIPAddress_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIPAddress_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5dc54dc133694e6ca1812e5e56e958df388a0_003F68_003F0bc1a452_003FIPAddress_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIWebSocketConnectionInfo_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003F54_003Ff0e67f89_003FIWebSocketConnectionInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIWebSocketConnection_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003Fc1_003Fb154f2eb_003FIWebSocketConnection_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIWebSocketConnection_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003Fc1_003Fb154f2eb_003FIWebSocketConnection_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AIWebSocketConnection_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003Fc1_003Fb154f2eb_003FIWebSocketConnection_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKernelTraceEventParser_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F24_003Fd19d02f2_003FKernelTraceEventParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKernelTraceEventParser_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F24_003Fd19d02f2_003FKernelTraceEventParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKernelTraceEventParser_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F24_003Fd19d02f2_003FKernelTraceEventParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AKernelTraceEventParser_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F24_003Fd19d02f2_003FKernelTraceEventParser_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALazy_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F74_003F173162e6_003FLazy_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALazy_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003F74_003F173162e6_003FLazy_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
@@ -39,6 +43,7 @@
|
|||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEventSession_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4e_003F99d3e433_003FTraceEventSession_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEventSession_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4e_003F99d3e433_003FTraceEventSession_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEvent_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4d_003F09175cdc_003FTraceEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEvent_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4d_003F09175cdc_003FTraceEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEvent_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4d_003F09175cdc_003FTraceEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEvent_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F4d_003F09175cdc_003FTraceEvent_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWebSocketServer_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa7d96aff8e344c1d9aa8042f229d493cae00_003Fc6_003F2f09550a_003FWebSocketServer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWebView2_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8aca2f2c90e1454c825fc8b69c53a97e14268_003F06_003F22dc0e77_003FWebView2_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AWebView2_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F8aca2f2c90e1454c825fc8b69c53a97e14268_003F06_003F22dc0e77_003FWebView2_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||||
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=f4a8c497_002D43fb_002D4de1_002D9ffa_002D84076d7db2c5/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=f4a8c497_002D43fb_002D4de1_002D9ffa_002D84076d7db2c5/@EntryIndexedValue"><SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session">
|
||||||
<TestAncestor>
|
<TestAncestor>
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
using System.Configuration;
|
using System.Configuration;
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Application.Utils;
|
using Application.Utils;
|
||||||
using Common;
|
using Common;
|
||||||
using Common.Logger;
|
using Common.Logger;
|
||||||
|
using Common.Net.HttpConn;
|
||||||
|
using Common.Net.Models;
|
||||||
using Common.Net.WebSocketConn;
|
using Common.Net.WebSocketConn;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
@@ -120,9 +126,76 @@ public partial class App : System.Windows.Application
|
|||||||
AppConfig.Instance.WebSocketPath = $"ws://127.0.0.1:{port}";
|
AppConfig.Instance.WebSocketPath = $"ws://127.0.0.1:{port}";
|
||||||
Log.Information4Ctx($"服务启动在端口: {AppConfig.Instance.WebSocketPort}");
|
Log.Information4Ctx($"服务启动在端口: {AppConfig.Instance.WebSocketPort}");
|
||||||
Log.Information($"服务完整地址: {AppConfig.Instance.WebSocketPath}");
|
Log.Information($"服务完整地址: {AppConfig.Instance.WebSocketPath}");
|
||||||
// TODO 2025年5月28日 22点25分 :开启 Http 网络本地服务,提供网页访问
|
|
||||||
|
|
||||||
// 启动WebSocket服务器
|
// 启动WebSocket服务器
|
||||||
WebSocketManager.Instance.Start(AppConfig.Instance.WebSocketPath);
|
WebSocketManager.Instance.Start(AppConfig.Instance.WebSocketPath);
|
||||||
|
|
||||||
|
// 启动 http 服务
|
||||||
|
Task.Run(() => { _ = StartHttpServer(); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task StartHttpServer()
|
||||||
|
{
|
||||||
|
// 开启 http 服务
|
||||||
|
var server = new HttpServer("http://localhost:8268/");
|
||||||
|
// 添加中间件
|
||||||
|
server.UseMiddleware(Middlewares.RequestLogging);
|
||||||
|
server.UseMiddleware(Middlewares.Cors);
|
||||||
|
|
||||||
|
// 添加路由
|
||||||
|
server.Get("/api",
|
||||||
|
async (context) => { await context.Response.WriteJsonAsync(new { message = "Hi!" }); });
|
||||||
|
|
||||||
|
// 订阅软件列表
|
||||||
|
server.Post("/api/subscribe", async (context) =>
|
||||||
|
{
|
||||||
|
// 正确的做法:只处理请求体数据
|
||||||
|
if (string.IsNullOrEmpty(context.RequestBody))
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Message = "请求体不能为空",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析请求数据
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var request = context.GetRequestBody<string>();
|
||||||
|
Log.Warning(request);
|
||||||
|
}
|
||||||
|
catch (JsonException ex)
|
||||||
|
{
|
||||||
|
context.Response.StatusCode = 400;
|
||||||
|
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||||
|
{
|
||||||
|
Success = false,
|
||||||
|
Message = $"请求数据格式错误: {ex.Message}",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回响应 - 只序列化纯数据对象
|
||||||
|
context.Response.StatusCode = 200;
|
||||||
|
await context.Response.WriteJsonAsync(new ResponseModel<string>
|
||||||
|
{
|
||||||
|
Success = true,
|
||||||
|
Data = "成功",
|
||||||
|
Message = "订阅成功",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 启动服务器
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await server.StartAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Server error: {ex.Message}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11,7 +11,6 @@ using Infrastructure.utils;
|
|||||||
using Utils.ETW;
|
using Utils.ETW;
|
||||||
using Utils.ETW.Core;
|
using Utils.ETW.Core;
|
||||||
using Utils.ETW.Etw;
|
using Utils.ETW.Etw;
|
||||||
using WinDivertNet.WinDivertWrapper;
|
|
||||||
|
|
||||||
namespace Shell.Views;
|
namespace Shell.Views;
|
||||||
|
|
||||||
@@ -112,9 +111,9 @@ public partial class WebPanel : UserControl
|
|||||||
case "GetAllTcpConnections":
|
case "GetAllTcpConnections":
|
||||||
NetUtils.GetAllTcpConnections();
|
NetUtils.GetAllTcpConnections();
|
||||||
break;
|
break;
|
||||||
case "PacketSnifferStart":
|
// case "PacketSnifferStart":
|
||||||
PacketSniffer.Start();
|
// PacketSniffer.Start();
|
||||||
break;
|
// break;
|
||||||
case "GetWebSocketPath":
|
case "GetWebSocketPath":
|
||||||
WebSocketPath();
|
WebSocketPath();
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Infrastructure.Models;
|
||||||
using Utils.ETW.Models;
|
using Utils.ETW.Models;
|
||||||
|
|
||||||
namespace Utils.ETW.Etw;
|
namespace Utils.ETW.Etw;
|
||||||
@@ -9,11 +10,7 @@ namespace Utils.ETW.Etw;
|
|||||||
public class ApplicationInfo
|
public class ApplicationInfo
|
||||||
{
|
{
|
||||||
public int ProcessId { get; set; }
|
public int ProcessId { get; set; }
|
||||||
public string ApplicationName { get; set; }
|
public ProgramInfo ProgramInfo { get; set; }
|
||||||
public string ApplicationPath { get; set; }
|
|
||||||
public string Version { get; set; }
|
|
||||||
public string Company { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public DateTime FirstSeenTime { get; set; }
|
public DateTime FirstSeenTime { get; set; }
|
||||||
public DateTime LastUpdateTime { get; set; }
|
public DateTime LastUpdateTime { get; set; }
|
||||||
}
|
}
|
||||||
@@ -115,10 +112,7 @@ public class NetworkMonitorSnapshot
|
|||||||
public class ApplicationSnapshot
|
public class ApplicationSnapshot
|
||||||
{
|
{
|
||||||
public int ProcessId { get; set; }
|
public int ProcessId { get; set; }
|
||||||
public string ApplicationName { get; set; }
|
public ProgramInfo? ProgramInfo { get; set; }
|
||||||
public string ApplicationPath { get; set; }
|
|
||||||
public string Version { get; set; }
|
|
||||||
public string ProcessName { get; set; }
|
|
||||||
public DateTime FirstSeenTime { get; set; }
|
public DateTime FirstSeenTime { get; set; }
|
||||||
public DateTime LastActiveTime { get; set; }
|
public DateTime LastActiveTime { get; set; }
|
||||||
public List<ConnectionSnapshot> Connections { get; set; }
|
public List<ConnectionSnapshot> Connections { get; set; }
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Infrastructure.utils;
|
||||||
using Utils.ETW.Core;
|
using Utils.ETW.Core;
|
||||||
using Utils.ETW.Models;
|
using Utils.ETW.Models;
|
||||||
|
|
||||||
@@ -270,27 +271,15 @@ public class EnhancedEtwNetworkManager : IDisposable
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 获取进程详细信息
|
// 获取进程详细信息
|
||||||
using (var process = Process.GetProcessById(processInfo.ProcessId))
|
var inspectProcess = SysInfoUtils.InspectProcess(processInfo.ProcessId);
|
||||||
{
|
|
||||||
var mainModule = process.MainModule;
|
|
||||||
if (mainModule != null)
|
|
||||||
{
|
|
||||||
var appPath = mainModule.FileName;
|
|
||||||
var appName = Path.GetFileNameWithoutExtension(appPath);
|
|
||||||
var version = mainModule.FileVersionInfo.FileVersion;
|
|
||||||
var company = mainModule.FileVersionInfo.CompanyName;
|
|
||||||
|
|
||||||
// 更新应用程序信息
|
// 更新应用程序信息
|
||||||
GlobalNetworkMonitor.Instance.UpdateApplicationInfo(
|
GlobalNetworkMonitor.Instance.UpdateApplicationInfo(
|
||||||
processInfo.ProcessId,
|
processInfo.ProcessId,
|
||||||
appName,
|
inspectProcess
|
||||||
appPath,
|
);
|
||||||
version
|
|
||||||
);
|
|
||||||
|
|
||||||
processInfo.NeedsUpdate = false;
|
processInfo.NeedsUpdate = false;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -366,10 +355,11 @@ public class EnhancedEtwNetworkManager : IDisposable
|
|||||||
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
|
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
|
||||||
foreach (var app in snapshot.Applications)
|
foreach (var app in snapshot.Applications)
|
||||||
{
|
{
|
||||||
foreach (var conn in app.Connections.Where(c => !c.IsActive && c.Duration > TimeSpan.FromMinutes(5)))
|
foreach (var conn in app.Connections.Where(c =>
|
||||||
|
!c.IsActive && c.Duration > TimeSpan.FromMinutes(5)))
|
||||||
{
|
{
|
||||||
// 这里可以添加清理逻辑
|
// 这里可以添加清理逻辑
|
||||||
Console.WriteLine($"清理过期连接: {app.ProcessName} - {conn.RemoteIp}:{conn.RemotePort}");
|
Console.WriteLine($"清理过期连接: {app.ProgramInfo?.ProductName} - {conn.RemoteIp}:{conn.RemotePort}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
using Infrastructure.Models;
|
||||||
using Utils.ETW.Models;
|
using Utils.ETW.Models;
|
||||||
|
|
||||||
namespace Utils.ETW.Etw;
|
namespace Utils.ETW.Etw;
|
||||||
@@ -63,7 +64,7 @@ public sealed class GlobalNetworkMonitor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 更新应用程序信息
|
/// 更新应用程序信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void UpdateApplicationInfo(int processId, string appName, string appPath, string version = null)
|
public void UpdateApplicationInfo(int processId, ProgramInfo info)
|
||||||
{
|
{
|
||||||
_lock.EnterWriteLock();
|
_lock.EnterWriteLock();
|
||||||
try
|
try
|
||||||
@@ -72,17 +73,13 @@ public sealed class GlobalNetworkMonitor
|
|||||||
new ApplicationInfo
|
new ApplicationInfo
|
||||||
{
|
{
|
||||||
ProcessId = processId,
|
ProcessId = processId,
|
||||||
ApplicationName = appName,
|
ProgramInfo = info,
|
||||||
ApplicationPath = appPath,
|
|
||||||
Version = version,
|
|
||||||
FirstSeenTime = DateTime.Now,
|
FirstSeenTime = DateTime.Now,
|
||||||
LastUpdateTime = DateTime.Now
|
LastUpdateTime = DateTime.Now
|
||||||
},
|
},
|
||||||
(key, existing) =>
|
(key, existing) =>
|
||||||
{
|
{
|
||||||
existing.LastUpdateTime = DateTime.Now;
|
existing.LastUpdateTime = DateTime.Now;
|
||||||
if (!string.IsNullOrEmpty(version))
|
|
||||||
existing.Version = version;
|
|
||||||
return existing;
|
return existing;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -283,10 +280,7 @@ public sealed class GlobalNetworkMonitor
|
|||||||
var appSnapshot = new ApplicationSnapshot
|
var appSnapshot = new ApplicationSnapshot
|
||||||
{
|
{
|
||||||
ProcessId = processId,
|
ProcessId = processId,
|
||||||
ApplicationName = appInfo?.ApplicationName ?? processInfo.ProcessName,
|
ProgramInfo = appInfo?.ProgramInfo,
|
||||||
ApplicationPath = appInfo?.ApplicationPath ?? "Unknown",
|
|
||||||
Version = appInfo?.Version ?? "Unknown",
|
|
||||||
ProcessName = processInfo.ProcessName,
|
|
||||||
FirstSeenTime = processInfo.FirstSeenTime,
|
FirstSeenTime = processInfo.FirstSeenTime,
|
||||||
LastActiveTime = processInfo.LastActiveTime,
|
LastActiveTime = processInfo.LastActiveTime,
|
||||||
Connections = new List<ConnectionSnapshot>()
|
Connections = new List<ConnectionSnapshot>()
|
||||||
@@ -386,6 +380,15 @@ public sealed class GlobalNetworkMonitor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有应用程序【有网络活动】
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<ProgramInfo> GetAllPrograms()
|
||||||
|
{
|
||||||
|
return _applications.Values.ToList().Select(applicationInfo => applicationInfo.ProgramInfo).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region 私有辅助方法
|
#region 私有辅助方法
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Common\Common.csproj" />
|
<ProjectReference Include="..\Common\Common.csproj" />
|
||||||
|
<ProjectReference Include="..\Infrastructure\Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"sdk": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"rollForward": "latestMajor",
|
||||||
|
"allowPrerelease": true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user