A:增加Websocke消息处理
This commit is contained in:
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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user