A:增加Websocke消息处理

This commit is contained in:
jimmy committed 2025-06-27 14:05:03 +08:00
1 parent d6ccf139e2
commit b743c908b6
9 files changed
+527 -32

No files matched your search

@@ -15,6 +15,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Common.Net\Common.Net.csproj" />
<ProjectReference Include="..\Utils.ETW\Utils.ETW.csproj" />
</ItemGroup>
@@ -1,7 +1,10 @@
using System.Collections.Concurrent;
using System.Text.Json;
using System.Text.Json.Serialization;
using Common;
using Common.Logger;
using Common.Net.WebSocketConn;
using Infrastructure.Models;
using Utils.ETW.Etw;
namespace Shell;
@@ -50,12 +53,15 @@ public class DispatchEngine
ApplicationInfoDispatch.TryRemove(clientId, out _);
}
// 添加这个字段来保持Timer的强引用;Timer 对象没有强引用,会被垃圾回收器回收。
private Timer _applicationInfoTimer;
/// <summary>
/// 软件信息分发
/// </summary>
public void ApplicationInfoDistribute()
{
var timer = new Timer(state =>
_applicationInfoTimer = new Timer(state =>
{
if (ApplicationInfoDispatch.Count == 0)
{
@@ -64,7 +70,71 @@ public class DispatchEngine
// 获取信息
var programInfos = GlobalNetworkMonitor.Instance.GetAllPrograms();
var serialize = JsonSerializer.Serialize(programInfos);
var grouped = programInfos
.GroupBy(p => p.MainModulePath ?? p.ProcessName)
.ToDictionary(g => g.Key, g => g.ToList());
var list = grouped.Values.ToList();
var appInfoList = new List<ApplicationInfoModel>();
foreach (var infose in list)
{
if (infose.Count == 0)
{
continue;
}
ApplicationInfoModel pi = new ApplicationInfoModel
{
Id = "null"
};
var pids = new List<int>();
var startTime = DateTime.Now;
var isExit = true;
var useMemory = 0L;
var threadCount = 0;
var id = "";
foreach (var programInfo in infose)
{
pi.ProcessName ??= programInfo.ProcessName;
pi.ExitTime ??= programInfo.ExitTime;
pi.ExitCode ??= programInfo.ExitCode;
pi.MainModulePath ??= programInfo.MainModulePath;
pi.MainModuleName ??= programInfo.MainModuleName;
pi.FileDescription ??= programInfo.FileDescription;
pi.ProductName ??= programInfo.ProductName;
pi.CompanyName ??= programInfo.CompanyName;
pi.Version ??= programInfo.Version;
pi.LegalCopyright ??= programInfo.LegalCopyright;
pi.IconBase64 = programInfo.IconBase64;
id += programInfo.ProcessId;
pids.Add(programInfo.ProcessId);
// 只记录最早的时间
if (programInfo.StartTime < startTime)
{
startTime = programInfo.StartTime;
}
// 全部退出才算退出
if (!programInfo.HasExited && isExit)
{
isExit = programInfo.HasExited;
}
useMemory += programInfo.UseMemory;
threadCount += programInfo.ThreadCount;
}
pi.Id = id;
pi.ProcessIds = pids;
pi.StartTime = startTime;
pi.HasExited = isExit;
pi.UseMemory = useMemory;
pi.ThreadCount = threadCount;
appInfoList.Add(pi);
}
var serialize = JsonSerializer.Serialize(appInfoList);
foreach (var keyValuePair in ApplicationInfoDispatch)
{
@@ -96,8 +166,9 @@ public class DispatchEngine
{
Success = true,
Data = serialize,
Message = "数据发送",
Timestamp = AppInfoLastSendTime[keyValuePair.Key]
Message = "数据发送123",
Timestamp = AppInfoLastSendTime[keyValuePair.Key],
Type = AppConfig.ApplicationInfoSubscribe
};
WebSocketManager.Instance.SendToClient(keyValuePair.Key, rm);
}
@@ -126,5 +197,4 @@ public class SubscriptionInfo
{
[JsonPropertyName("subscriptionType")] public string SubscriptionType { get; set; }
[JsonPropertyName("interval")] public int Interval { get; set; }
}
}
@@ -7,6 +7,18 @@ using Fleck;
namespace Common.Net.WebSocketConn;
// 连接关闭事件参数
public class ConnectionClosedEventArgs : EventArgs
{
public Guid SocketId { get; init; }
public string? Uuid { get; init; }
public DateTime ClosedAt { get; init; } = DateTime.Now;
public string? Reason { get; init; }
}
// 连接关闭委托
public delegate void ConnectionClosedHandler(ConnectionClosedEventArgs args);
// WebSocket管理器 - 单例模式
public class WebSocketManager
{
@@ -31,6 +43,11 @@ public class WebSocketManager
// 消息处理器字典
private readonly ConcurrentDictionary<string, Func<CommandMessage, IWebSocketConnection, Task>> _messageHandlers;
/// <summary>
/// 连接关闭事件
/// </summary>
public event ConnectionClosedHandler? ConnectionClosed;
private WebSocketManager()
{
_connections = new ConcurrentDictionary<Guid, ClientConnection>();
@@ -38,6 +55,44 @@ public class WebSocketManager
RegisterDefaultHandlers();
}
#region 连接关闭委托相关方法
/// <summary>
/// 订阅连接关闭事件
/// </summary>
/// <param name="handler">事件处理器</param>
public void SubscribeConnectionClosed(ConnectionClosedHandler handler)
{
ConnectionClosed += handler;
}
/// <summary>
/// 取消订阅连接关闭事件
/// </summary>
/// <param name="handler">事件处理器</param>
public void UnsubscribeConnectionClosed(ConnectionClosedHandler handler)
{
ConnectionClosed -= handler;
}
/// <summary>
/// 触发连接关闭事件
/// </summary>
/// <param name="args">事件参数</param>
private void OnConnectionClosedEvent(ConnectionClosedEventArgs args)
{
try
{
ConnectionClosed?.Invoke(args);
}
catch (Exception ex)
{
Log.Error($"处理连接关闭事件时出错: {ex.Message}");
}
}
#endregion
// 启动WebSocket服务器
public void Start(string url = "ws://127.0.0.1:8080")
{
@@ -82,6 +137,43 @@ public class WebSocketManager
socketConnection.Close();
var valueUuid = webSocketConnection.Value.Uuid;
_uuidToSocketId.TryRemove(valueUuid, out _);
// 触发连接关闭事件
OnConnectionClosedEvent(new ConnectionClosedEventArgs
{
SocketId = webSocketConnection.Key,
Uuid = valueUuid,
Reason = "服务器关闭"
});
}
}
/// <summary>
/// 主动关闭指定连接
/// </summary>
/// <param name="socketId">连接ID</param>
/// <param name="reason">关闭原因</param>
public async Task CloseConnection(Guid socketId, string reason = "主动关闭")
{
if (_connections.TryGetValue(socketId, out var connection))
{
connection.Socket.Close();
// OnConnectionClose会被自动调用,但我们可以在这里预先记录关闭原因
Log.Information($"主动关闭连接: {socketId}, 原因: {reason}");
}
}
/// <summary>
/// 主动关闭指定UUID的连接
/// </summary>
/// <param name="uuid">用户UUID</param>
/// <param name="reason">关闭原因</param>
public async Task CloseConnection(string uuid, string reason = "主动关闭")
{
if (_uuidToSocketId.TryGetValue(uuid, out var socketId))
{
await CloseConnection(socketId, reason);
}
}
@@ -153,15 +245,23 @@ public class WebSocketManager
private void OnConnectionClose(IWebSocketConnection socket)
{
_connections.TryRemove(socket.ConnectionInfo.Id, out var conn);
string? uuid = null;
if (conn?.Uuid != null)
{
uuid = conn.Uuid;
_uuidToSocketId.TryRemove(conn.Uuid, out _);
// 清空订阅
// conn.Uuid;
}
Log.Information($"客户端断开: {socket.ConnectionInfo.Id}");
// 触发连接关闭事件
OnConnectionClosedEvent(new ConnectionClosedEventArgs
{
SocketId = socket.ConnectionInfo.Id,
Uuid = uuid,
Reason = "客户端断开连接"
});
}
// 接收消息
@@ -299,6 +399,27 @@ public class WebSocketManager
// 获取所有连接ID
public Guid[] GetConnectionIds() => _connections.Keys.ToArray();
/// <summary>
/// 获取指定UUID的连接信息
/// </summary>
public ClientConnection? GetConnection(string uuid)
{
if (_uuidToSocketId.TryGetValue(uuid, out var socketId) &&
_connections.TryGetValue(socketId, out var connection))
{
return connection;
}
return null;
}
/// <summary>
/// 检查指定UUID的连接是否存在
/// </summary>
public bool IsConnected(string uuid)
{
return _uuidToSocketId.ContainsKey(uuid);
}
#region 业务逻辑示例方法(需要根据实际需求实现)
private object GetNetworkStatus()
@@ -361,4 +482,46 @@ public class ClientConnection
public Guid SocketId { get; init; }
public string Uuid { get; init; }
public IWebSocketConnection Socket { get; init; }
}
// 使用示例类
public static class WebSocketManagerUsageExample
{
public static void Initialize()
{
var wsManager = WebSocketManager.Instance;
// 订阅连接关闭事件
wsManager.SubscribeConnectionClosed(OnConnectionClosed);
// 启动服务器
wsManager.Start();
}
private static void OnConnectionClosed(ConnectionClosedEventArgs args)
{
Console.WriteLine($"连接已关闭:");
Console.WriteLine($" Socket ID: {args.SocketId}");
Console.WriteLine($" UUID: {args.Uuid ?? "未知"}");
Console.WriteLine($" 关闭时间: {args.ClosedAt}");
Console.WriteLine($" 关闭原因: {args.Reason ?? "未知"}");
// 在这里可以执行清理逻辑,比如:
// - 清理用户相关的缓存数据
// - 更新用户在线状态
// - 记录用户离线时间
// - 通知其他相关服务
// 示例:清理用户数据
if (!string.IsNullOrEmpty(args.Uuid))
{
CleanupUserData(args.Uuid);
}
}
private static void CleanupUserData(string uuid)
{
// 实现用户数据清理逻辑
Console.WriteLine($"清理用户 {uuid} 的相关数据");
}
}
@@ -26,15 +26,20 @@ public class ProgramInfo
/// </summary>
public bool HasExited { get; set; }
/*
ExitTime 和 ExitCode 这两个属性只有在进程已经退出后才能访问。对于正在运行的进程,
访问这些属性会抛出 "Process must exit before requested information can be determined" 异常。
*/
/// <summary>
/// 退出时间
/// </summary>
public DateTime ExitTime { get; set; }
public DateTime? ExitTime { get; set; }
/// <summary>
/// 退出代码
/// </summary>
public int ExitCode { get; set; }
public int? ExitCode { get; set; }
/// <summary>
/// 占用内存
@@ -86,3 +91,87 @@ public class ProgramInfo
/// </summary>
public string IconBase64 { get; set; } = "";
}
public class ApplicationInfoModel
{
public required string Id { get; set; }
/// <summary>
/// 进程名称
/// </summary>
public string ProcessName { get; set; } = "";
/// <summary>
/// 进程ID
/// </summary>
public List<int> ProcessIds { get; set; }
/// <summary>
/// 启动时间
/// </summary>
public DateTime StartTime { get; set; }
/// <summary>
/// 是否退出
/// </summary>
public bool HasExited { get; set; }
/// <summary>
/// 退出时间
/// </summary>
public DateTime? ExitTime { get; set; }
/// <summary>
/// 退出代码
/// </summary>
public int? ExitCode { get; set; }
/// <summary>
/// 占用内存
/// </summary>
public long UseMemory { get; set; }
/// <summary>
/// 线程数
/// </summary>
public int ThreadCount { get; set; }
/// <summary>
/// 主模块路径
/// </summary>
public string? MainModulePath { get; set; }
/// <summary>
/// 启动文件名
/// </summary>
public string? MainModuleName { get; set; }
/// <summary>
/// 文件描述
/// </summary>
public string? FileDescription { get; set; }
/// <summary>
/// 产品名称
/// </summary>
public string? ProductName { get; set; }
/// <summary>
/// 公司名称
/// </summary>
public string? CompanyName { get; set; }
/// <summary>
/// 版本号
/// </summary>
public string? Version { get; set; }
/// <summary>
/// 版权
/// </summary>
public string? LegalCopyright { get; set; }
/// <summary>
/// 图标
/// </summary>
public string IconBase64 { get; set; } = "";
}
@@ -56,6 +56,12 @@ public static class SysInfoUtils
}
/// <summary>
/// 获取指定进程的信息
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
/// <exception cref="ExceptionExpand"></exception>
/// <summary>
/// 获取指定进程的信息
/// </summary>
@@ -84,47 +90,185 @@ public static class SysInfoUtils
var exeInfo = new ProgramInfo
{
ProcessName = proc.ProcessName,
ProcessId = proc.Id,
StartTime = proc.StartTime,
HasExited = proc.HasExited,
ExitTime = proc.ExitTime,
ExitCode = proc.ExitCode,
UseMemory = proc.WorkingSet64,
ThreadCount = proc.Threads.Count,
MainModulePath = proc.MainModule?.FileName,
MainModuleName = proc.MainModule?.ModuleName
ProcessId = proc.Id
};
// MainModule 是一个涉及 native 调用的属性,不建议频繁调用,尤其在枚举大量进程时可能影响性能。
// 安全获取启动时间
try
{
exeInfo.StartTime = proc.StartTime;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的启动时间: {ex.Message}");
exeInfo.StartTime = DateTime.MinValue;
}
// 安全获取退出状态
try
{
exeInfo.HasExited = proc.HasExited;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的退出状态: {ex.Message}");
exeInfo.HasExited = false;
}
// 安全获取内存使用量
try
{
exeInfo.UseMemory = proc.WorkingSet64;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的内存信息: {ex.Message}");
exeInfo.UseMemory = 0;
}
// 安全获取线程数
try
{
exeInfo.ThreadCount = proc.Threads.Count;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的线程信息: {ex.Message}");
exeInfo.ThreadCount = 0;
}
// 安全获取主模块信息
try
{
var mainModule = proc.MainModule;
exeInfo.MainModulePath = mainModule?.FileName;
exeInfo.MainModuleName = mainModule?.ModuleName;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的模块信息!: {ex.Message}");
exeInfo.MainModulePath = null;
exeInfo.MainModuleName = proc.ProcessName; // 使用进程名作为备用
}
// 只有在进程已退出时才能访问 ExitTime 和 ExitCode
if (exeInfo.HasExited)
{
try
{
exeInfo.ExitTime = proc.ExitTime;
exeInfo.ExitCode = proc.ExitCode;
}
catch (Exception ex)
{
// 如果仍然无法获取退出信息,记录日志但不抛出异常
Log.Information($"无法获取进程 {pid} 的退出信息: {ex.Message}");
exeInfo.ExitTime = null;
exeInfo.ExitCode = null;
}
}
else
{
// 对于正在运行的进程,设置默认值
exeInfo.ExitTime = null; // 或者 DateTime.MinValue,取决于 ProgramInfo.ExitTime 的类型
exeInfo.ExitCode = null; // 或者 0,取决于 ProgramInfo.ExitCode 的类型
}
// MainModule 是一个涉及 native 调用的属性,不建议频繁调用,尤其在枚举大量进程时可能影响性能。
if (exeInfo.MainModulePath != null)
{
var versionInfo = FileVersionInfo.GetVersionInfo(exeInfo.MainModulePath);
try
{
var versionInfo = FileVersionInfo.GetVersionInfo(exeInfo.MainModulePath);
exeInfo.FileDescription = versionInfo.FileDescription;
exeInfo.ProductName = versionInfo.ProductName;
exeInfo.CompanyName = versionInfo.CompanyName;
exeInfo.Version = versionInfo.FileVersion;
exeInfo.LegalCopyright = versionInfo.LegalCopyright;
exeInfo.FileDescription = versionInfo.FileDescription;
exeInfo.ProductName = versionInfo.ProductName;
exeInfo.CompanyName = versionInfo.CompanyName;
exeInfo.Version = versionInfo.FileVersion;
exeInfo.LegalCopyright = versionInfo.LegalCopyright;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的版本信息: {ex.Message}");
}
}
// 获取软件 Icon 【不一定存在】
var iconBase64 = IconHelper.GetIconBase64(exeInfo.MainModulePath);
exeInfo.IconBase64 = iconBase64;
try
{
var iconBase64 = IconHelper.GetIconBase64(exeInfo.MainModulePath);
exeInfo.IconBase64 = iconBase64;
}
catch (Exception ex)
{
Log.Information($"无法获取进程 {pid} 的图标: {ex.Message}");
}
#endregion
ProcessCache.Instance.Set(pck, exeInfo);
return exeInfo;
}
// 只捕获能遇见的异常
// 捕获各种可能的异常
catch (ArgumentException ex)
{
Log.Information($"获取进程信息失败:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
catch (InvalidOperationException ex)
{
Log.Information($"进程 {pid} 已退出或无法访问:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
catch (System.ComponentModel.Win32Exception ex)
{
Log.Information($"无权限访问进程 {pid}:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
catch (UnauthorizedAccessException ex)
{
Log.Information($"拒绝访问进程 {pid}:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
catch (Exception ex)
{
Log.Information($"获取进程 {pid} 信息时发生未知错误:{ex.Message}");
throw ExceptionEnum.ProcessGetException;
}
}
/// <summary>
/// 获取程序路径(名称)
/// </summary>
/// <param name="pid"></param>
/// <returns></returns>
public static string GetProcessPath(int pid)
{
var proc = Process.GetProcessById(pid);
var mainModule = proc.MainModule;
if (mainModule == null)
{
return proc.ProcessName;
}
else
{
return mainModule.FileName;
}
}
// WMI 查询(能拿到路径,但性能稍差)
// static string GetProcessPathWmi(int pid)
// {
// using var searcher = new ManagementObjectSearcher(
// $"SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = {pid}");
//
// foreach (ManagementObject obj in searcher.Get())
// {
// return obj["ExecutablePath"]?.ToString();
// }
//
// return null;
// }
private static string FormatBytes(long bytes)
{
string[] sizes = ["B", "KB", "MB", "GB", "TB"];
@@ -138,4 +282,4 @@ public static class SysInfoUtils
return $"{len:0.##} {sizes[order]}";
}
}
}
@@ -12,6 +12,7 @@
<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_003AETWTraceEventSource_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F01_003F4bae5ee3_003FETWTraceEventSource_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AETWTraceEventSource_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F01_003F4bae5ee3_003FETWTraceEventSource_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AExecutionContext_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F9eda537f15ea23cdfae523c19e87eb303a3ded88937ae7e55919387a43f70_003FExecutionContext_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_003AFuture_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F6f90c6c13479b8c2a5be98f3d75dfc3bd885a055652d8a32904ca2448132949e_003FFuture_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
@@ -28,6 +29,7 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ALogger_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F59d0b425a1244469855c0039f03f864c27e00_003F43_003F8a29b095_003FLogger_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AMonitor_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fb5_003F0c446809_003FMonitor_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkInterface_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F9c72a65889eb40ae9d8e0f130d1572e0268a0_003F34_003F49f5e6ff_003FNetworkInterface_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProcessModule_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fa70eaad10e4f42d4a1f24ff3865c6c6252928_003Fec_003F0881d57a_003FProcessModule_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AProcess_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4a26a752ec6249c4a090905d31c0cdfa528a0_003F8f_003F7037e590_003FProcess_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueue_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fa1_003F352e385c_003FQueue_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AQueue_00601_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F5aeb6167299d4cfba30c86624130edbcc90938_003F2b_003Fb4ef3890_003FQueue_00601_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
+24
View File
@@ -16,6 +16,7 @@ using Common.Net.Models;
using Common.Net.WebSocketConn;
using Microsoft.Extensions.Logging;
using Serilog.Events;
using Utils.ETW.Etw;
namespace Shell;
@@ -131,11 +132,34 @@ public partial class App : System.Windows.Application
// 启动WebSocket服务器
WebSocketManager.Instance.Start(AppConfig.Instance.WebSocketPath);
// 订阅信息关闭服务
WebSocketManager.Instance.SubscribeConnectionClosed((args =>
{
if (args.Uuid != null) DispatchEngine.Instance.DeleteApplicationInfo(args.Uuid);
}
));
// 开启 WebSocket 定时发送服务
DispatchEngine.Instance.ApplicationInfoDistribute();
// 启动 http 服务
Task.Run(() => { _ = StartHttpServer(); });
// 开启监听
NewMethod();
}
private static async Task NewMethod()
{
if (!SysHelper.IsAdministrator())
{
Console.WriteLine("此程序需要管理员权限才能运行ETW监控!");
Console.WriteLine("请以管理员身份重新运行程序。");
Console.ReadKey();
return;
}
var _networkManager = new EnhancedEtwNetworkManager();
_networkManager.StartMonitoring();
}
private static async Task StartHttpServer()
@@ -264,7 +264,8 @@ public class EnhancedEtwNetworkManager : IDisposable
{
try
{
foreach (var kvp in _processCache.Where(p => p.Value.NeedsUpdate))
var keyValuePairs = _processCache.Where(p => p.Value.NeedsUpdate);
foreach (var kvp in keyValuePairs)
{
var processInfo = kvp.Value;
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using System.Net;
using Infrastructure.Models;
using Infrastructure.utils;
using Utils.ETW.Models;
namespace Utils.ETW.Etw;