A:基础实现 及调整
This commit is contained in:
1 parent
a6922cea36
commit
04e912a830
6 files changed
+54
-94
No files matched your search
@@ -8,16 +8,14 @@ namespace Infrastructure.GlobalCaches;
|
||||
/// </summary>
|
||||
public sealed class ProcessCache
|
||||
{
|
||||
private static readonly Lazy<ProcessCache> _instance = new Lazy<ProcessCache>(() => new ProcessCache());
|
||||
private static readonly Lazy<ProcessCache> _instance = new(() => new ProcessCache());
|
||||
|
||||
public static ProcessCache Instance => _instance.Value;
|
||||
|
||||
public record ProcessCacheKey(int Pid, DateTime StartTime);
|
||||
|
||||
public ProcessCacheKey GetProcessKey(int pid)
|
||||
public static string GetProcessKey(int pid)
|
||||
{
|
||||
var process = Process.GetProcessById(pid);
|
||||
return new ProcessCacheKey(pid, process.StartTime);
|
||||
return $"{pid}-{process.StartTime:yyyyMMddHHmmss}";
|
||||
}
|
||||
|
||||
// 私有构造函数,禁止外部创建实例
|
||||
@@ -26,11 +24,13 @@ public sealed class ProcessCache
|
||||
// 初始化缓存等操作
|
||||
}
|
||||
|
||||
// 示例缓存字段
|
||||
private readonly Dictionary<ProcessCacheKey, ProgramInfo> _cache = new Dictionary<ProcessCacheKey, ProgramInfo>();
|
||||
/// <summary>
|
||||
/// 缓存字典【给定初始量 1000 ,后期可根据需求调整,避免频繁扩容】
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, ProgramInfo> _cache = new(1000);
|
||||
|
||||
// 设置缓存
|
||||
public void Set(ProcessCacheKey key, ProgramInfo value)
|
||||
public void Set(string key, ProgramInfo value)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
@@ -39,7 +39,7 @@ public sealed class ProcessCache
|
||||
}
|
||||
|
||||
// 获取缓存
|
||||
public ProgramInfo? Get(ProcessCacheKey key)
|
||||
public ProgramInfo? Get(string key)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
@@ -48,7 +48,7 @@ public sealed class ProcessCache
|
||||
}
|
||||
|
||||
// 移除缓存
|
||||
public void Remove(ProcessCacheKey key)
|
||||
public void Remove(string key)
|
||||
{
|
||||
lock (_cache)
|
||||
{
|
||||
@@ -56,3 +56,26 @@ public sealed class ProcessCache
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
PID 重用问题:
|
||||
|
||||
🧠 背景 recap:
|
||||
操作系统(如 Windows)中的每个连接通常可以获取一个 PID。
|
||||
但由于:
|
||||
|
||||
进程退出后,PID 会被操作系统复用(可能很快)
|
||||
|
||||
某些连接(如 TIME_WAIT、CLOSE_WAIT)在进程退出后仍然保留一段时间
|
||||
因此:不能仅仅根据 PID 匹配连接与进程。
|
||||
|
||||
✅ 解决方法:引入 进程启动时间 + 连接时间戳 双重判断
|
||||
✅ 核心原则:
|
||||
一个连接只能属于:连接开始时间 ≥ 进程启动时间 的进程
|
||||
|
||||
❗反面例子:
|
||||
如果连接时间是 18:00
|
||||
但 PID 对应的进程启动时间是 18:10
|
||||
→ 说明这个进程是后来启动的(PID 被重用了)
|
||||
→ ❌ 不应该关联这条连接
|
||||
|
||||
*/
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Common\Common.csproj" />
|
||||
<ProjectReference Include="..\Utils.ETW\Utils.ETW.csproj" />
|
||||
<ProjectReference Include="..\WinDivertNet\WinDivertNet.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
using Utils.ETW.Models;
|
||||
|
||||
namespace Infrastructure.Models;
|
||||
|
||||
/// <summary>
|
||||
/// 进程信息【软件信息】
|
||||
/// </summary>
|
||||
public class ProgramInfo
|
||||
{
|
||||
/// <summary>
|
||||
@@ -82,74 +87,3 @@ public class ProgramInfo
|
||||
/// </summary>
|
||||
public string IconBase64 { get; set; } = "";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 网络信息
|
||||
/// </summary>
|
||||
public class NetInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 进程 ID
|
||||
/// </summary>
|
||||
public int Pid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 线程 ID
|
||||
/// </summary>
|
||||
public int Tid { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 数据方向 "Send" / "Recv"
|
||||
/// </summary>
|
||||
public string Direction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 初次一次活动事件
|
||||
/// </summary>
|
||||
public DateTime FirstSeen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最近一次活动事件
|
||||
/// </summary>
|
||||
public DateTime LastSeen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 连接状态
|
||||
/// </summary>
|
||||
public int State { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 源 IP
|
||||
/// </summary>
|
||||
public string SourceIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 源端口
|
||||
///</summary>
|
||||
public int SourcePort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标 IP
|
||||
///</summary>
|
||||
public string DestIp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 目标端口
|
||||
///</summary>
|
||||
public int DestPort { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 协议 TCP / UDP
|
||||
///</summary>
|
||||
public string Protocol { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 发送字节数
|
||||
/// </summary>
|
||||
public long TotalSendBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 接收字节数
|
||||
/// </summary>
|
||||
public long TotalReceiveBytes { get; set; }
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public static class IconHelper
|
||||
IntPtr hIcon = ExtractIcon(IntPtr.Zero, exePath, 0);
|
||||
if (hIcon == IntPtr.Zero) return "";
|
||||
|
||||
using Icon icon = Icon.FromHandle(hIcon);
|
||||
using System.Drawing.Icon icon = Icon.FromHandle(hIcon);
|
||||
using Bitmap bmp = icon.ToBitmap();
|
||||
using MemoryStream ms = new MemoryStream();
|
||||
// 保存为 PNG 格式
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using Common.Logger;
|
||||
|
||||
namespace Infrastructure.utils;
|
||||
|
||||
@@ -38,7 +39,7 @@ public static class NetUtils
|
||||
{
|
||||
if (TraceEventSession.IsElevated() == false)
|
||||
{
|
||||
Console.WriteLine("请以管理员身份运行此程序。");
|
||||
Log.Information("请以管理员身份运行此程序。");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -48,35 +49,35 @@ public static class NetUtils
|
||||
session.EnableKernelProvider(
|
||||
KernelTraceEventParser.Keywords.NetworkTCPIP);
|
||||
|
||||
Console.WriteLine("监听网络事件中(按 Ctrl+C 停止)...");
|
||||
Log.Information("监听网络事件中(按 Ctrl+C 停止)...");
|
||||
session.Source.Kernel.TcpIpConnect += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[TCP Connect] PID={data.ProcessID} {data.saddr}:{data.sport} -> {data.daddr}:{data.dport}");
|
||||
};
|
||||
session.Source.Kernel.TcpIpDisconnect += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[TCP Disconnect] PID={data.ProcessID} {data.saddr}:{data.sport} -> {data.daddr}:{data.dport}");
|
||||
};
|
||||
session.Source.Kernel.TcpIpSend += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[TCP Send] PID={data.ProcessID} {data.saddr}:{data.sport} -> {data.daddr}:{data.dport}, Size={data.size} bytes");
|
||||
};
|
||||
session.Source.Kernel.TcpIpRecv += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[TCP Recv] PID={data.ProcessID} {data.saddr}:{data.sport} <- {data.daddr}:{data.dport}, Size={data.size} bytes");
|
||||
};
|
||||
session.Source.Kernel.UdpIpSend += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[UDP Send] PID={data.ProcessID} {data.saddr}:{data.sport} -> {data.daddr}:{data.dport}, Size={data.size} bytes");
|
||||
};
|
||||
session.Source.Kernel.UdpIpRecv += data =>
|
||||
{
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"[UDP Recv] PID={data.ProcessID} {data.saddr}:{data.sport} <- {data.daddr}:{data.dport}, Size={data.size} bytes");
|
||||
};
|
||||
session.Source.Process(); // 开始监听
|
||||
@@ -108,7 +109,7 @@ public static class NetUtils
|
||||
int localPort = ntohs((ushort)row.localPort);
|
||||
int remotePort = ntohs((ushort)row.remotePort);
|
||||
|
||||
Console.WriteLine(
|
||||
Log.Information(
|
||||
$"PID: {row.owningPid}, {localIp}:{localPort} -> {remoteIp}:{remotePort}, State: {row.state}");
|
||||
rowPtr = IntPtr.Add(rowPtr, Marshal.SizeOf<MIB_TCPROW_OWNER_PID>());
|
||||
}
|
||||
@@ -192,7 +193,7 @@ public static class NetUtils
|
||||
IPAddress localIp = new IPAddress(row.localAddr);
|
||||
int localPort = ntohs1((ushort)row.localPort);
|
||||
|
||||
Console.WriteLine($"PID: {row.owningPid}, UDP {localIp}:{localPort}");
|
||||
Log.Information($"PID: {row.owningPid}, UDP {localIp}:{localPort}");
|
||||
rowPtr = IntPtr.Add(rowPtr, Marshal.SizeOf<MIB_UDPROW_OWNER_PID>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using Common;
|
||||
using Common.ExpandException;
|
||||
using Common.Logger;
|
||||
|
||||
namespace Infrastructure.utils;
|
||||
|
||||
@@ -69,7 +70,7 @@ public static class SysInfoUtils
|
||||
|
||||
#region 检查缓存
|
||||
|
||||
var pck = new ProcessCache.ProcessCacheKey(pid, proc.StartTime);
|
||||
var pck = ProcessCache.GetProcessKey(pid);
|
||||
var programInfo = ProcessCache.Instance.Get(pck);
|
||||
if (programInfo != null)
|
||||
{
|
||||
@@ -119,7 +120,7 @@ public static class SysInfoUtils
|
||||
// 只捕获能遇见的异常
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
Console.WriteLine($"获取进程信息失败:{ex.Message}");
|
||||
Log.Information($"获取进程信息失败:{ex.Message}");
|
||||
throw ExceptionEnum.ProcessGetException;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user