A:增加测试用例;增加统计函数。网络统计已基本可用

This commit is contained in:
jimmy committed 2025-06-18 16:50:59 +08:00
1 parent b48f3368b9
commit aa6c36655f
8 files changed
+1334 -11

No files matched your search

@@ -20,4 +20,10 @@ public static class SysHelper
listener.Stop();
return port;
}
public static bool IsAdministrator()
{
var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var principal = new System.Security.Principal.WindowsPrincipal(identity);
return principal.IsInRole(System.Security.Principal.WindowsBuiltInRole.Administrator);
}
}
@@ -2,19 +2,24 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AApplication_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6412d4331611499aab4eb63809a2a83bf60910_003Fd6_003F8ef46f2c_003FApplication_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AArray_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fc8_003F8670d075_003FArray_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ABoundedChannelOptions_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F6c1b38ac9eb24f67b802360dcd86fc07208b0_003Fd0_003Ff86ab164_003FBoundedChannelOptions_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ACancellationTokenSource_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Facc3e6e5f85e7174c16f6fd86bfc988df4815a736791e6f3d736ed79b8436e_003FCancellationTokenSource_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_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_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_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_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>
<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_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_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_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_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_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>
@@ -26,12 +31,14 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AReadOnlyCollectionBase_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F4c1fd115dbe5414db1b4da1de3e96c5819910_003F04_003Fcae9fe22_003FReadOnlyCollectionBase_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ASemaphoreSlim_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fe9_003F4d4110fd_003FSemaphoreSlim_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AString_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Ff1_003F7b5a67e3_003FString_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATask_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003Fa77b231cea33ff338c41dc7869d6c493d4dae137ff51e342173efa61d933_003FTask_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATcpIpConnectTraceData_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F93_003Fd6e6c065_003FTcpIpConnectTraceData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATcpIpSendTraceData_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F28_003Fce7c9cfa_003FTcpIpSendTraceData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimer_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fa8_003F04476824_003FTimer_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimer_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffe2ae574758f4da99bb3bfcba69a0a40b6928_003F7f_003Fb5cb1e21_003FTimer_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_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_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">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="Test1" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;TestAncestor&gt;&#xD;
@@ -10,6 +10,7 @@ using Common.Net.WebSocketConn;
using Infrastructure.utils;
using Utils.ETW;
using Utils.ETW.Core;
using Utils.ETW.Etw;
using WinDivertNet.WinDivertWrapper;
namespace Shell.Views;
@@ -25,7 +26,31 @@ public partial class WebPanel : UserControl
InitWebView();
// 注册管理 WebSocket 事件
WebSocketManger();
// WebSocketManger();
// ETW 信息获取
// 检查管理员权限
NewMethod();
}
private static async Task NewMethod()
{
if (!SysHelper.IsAdministrator())
{
Console.WriteLine("此程序需要管理员权限才能运行ETW监控!");
Console.WriteLine("请以管理员身份重新运行程序。");
Console.ReadKey();
return;
}
var example = new NetworkMonitorUsageExample();
example.RunExample();
// 创建监听实例
// var etwNetworkManger = new EtwNetworkManger();
// // 设置 ETW 监听
// etwNetworkManger.SetupEtwHandlers();
// etwNetworkManger.StartCapture();
}
private void WebSocketManger()
@@ -38,13 +63,10 @@ public partial class WebPanel : UserControl
Console.WriteLine("开始测试");
// 创建监听实例
var etwNetworkManger = new EtwNetworkManger();
// var etwNetworkManger = new EtwNetworkManger();
// 设置 ETW 监听
etwNetworkManger.SetupEtwHandlers();
// 开始监听
etwNetworkManger.StartCapture();
// etwNetworkManger.Initialize();
});
}
@@ -9,6 +9,9 @@ namespace Utils.ETW.Core;
// ETW网络事件处理器
public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisposable
{
/// <summary>
/// 此代码需要管理员权限
/// </summary>
private readonly TraceEventSession _session = new(sessionName);
private readonly ETWTraceEventSource _source = new(sessionName, TraceEventSourceType.Session);
@@ -271,11 +274,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
// 缓存进程信息,包括完整路径、命令行等
};
// 通用事件处理器,用于其他网络事件
_source.Dynamic.All += data =>
{
// 处理DNS、HTTP等其他网络事件
ProcessDynamicEvent(data);
};
_source.Dynamic.All += ProcessDynamicEvent;
}
@@ -0,0 +1,200 @@
using System.Net;
using Utils.ETW.Models;
namespace Utils.ETW.Etw;
/// <summary>
/// 应用程序信息
/// </summary>
public class ApplicationInfo
{
public int ProcessId { get; set; }
public string ApplicationName { 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 LastUpdateTime { get; set; }
}
/// <summary>
/// 进程网络信息
/// </summary>
public class ProcessNetworkInfo
{
public int ProcessId { get; set; }
public string ProcessName { get; set; }
public DateTime FirstSeenTime { get; set; }
public DateTime LastActiveTime { get; set; }
public List<string> ActiveConnections { get; set; } = new List<string>();
}
/// <summary>
/// 连接详细信息
/// </summary>
public class ConnectionInfo
{
public string ConnectionKey { get; set; }
public int ProcessId { get; set; }
public ProtocolType Protocol { get; set; }
/// <summary>
/// 本地 终结点
/// </summary>
public IPEndPoint LocalEndpoint { get; set; }
/// <summary>
/// 目标 终结点
/// </summary>
public IPEndPoint RemoteEndpoint { get; set; }
public ConnectionState State { get; set; }
public TrafficDirection Direction { get; set; }
public DateTime StartTime { get; set; }
public DateTime LastActiveTime { get; set; }
public long BytesSent { get; set; }
public long BytesReceived { get; set; }
public double CurrentSendSpeed { get; set; } // 字节/秒
public double CurrentReceiveSpeed { get; set; } // 字节/秒
public bool IsActive { get; set; }
// 速率计算辅助字段
public long LastBytesSent { get; set; }
public long LastBytesReceived { get; set; }
public DateTime LastSpeedCalculationTime { get; set; }
}
/// <summary>
/// DNS解析信息
/// </summary>
public class DnsResolveInfo
{
public string IpAddress { get; set; }
public string DomainName { get; set; }
public string QueryType { get; set; }
public DateTime ResolveTime { get; set; }
public DateTime LastUsedTime { get; set; }
public List<string> AlternativeDomains { get; set; } = new List<string>();
}
/// <summary>
/// 端口流量信息
/// </summary>
public class PortTrafficInfo
{
public int Port { get; set; }
public long BytesSent { get; set; }
public long BytesReceived { get; set; }
public long TotalBytes => BytesSent + BytesReceived;
public DateTime LastUpdateTime { get; set; }
}
/// <summary>
/// IP流量信息
/// </summary>
public class IpTrafficInfo
{
public string IpAddress { get; set; }
public long BytesSent { get; set; }
public long BytesReceived { get; set; }
public long TotalBytes => BytesSent + BytesReceived;
public DateTime LastUpdateTime { get; set; }
}
/// <summary>
/// 网络监控数据快照
/// </summary>
public class NetworkMonitorSnapshot
{
public DateTime SnapshotTime { get; set; }
public List<ApplicationSnapshot> Applications { get; set; }
public GlobalNetworkStats GlobalStats { get; set; }
}
/// <summary>
/// 应用程序快照
/// </summary>
public class ApplicationSnapshot
{
public int ProcessId { get; set; }
public string ApplicationName { get; set; }
public string ApplicationPath { get; set; }
public string Version { get; set; }
public string ProcessName { get; set; }
public DateTime FirstSeenTime { get; set; }
public DateTime LastActiveTime { get; set; }
public List<ConnectionSnapshot> Connections { get; set; }
// 统计信息
public int TotalConnections { get; set; }
public int ActiveConnections { get; set; }
public long TotalBytesSent { get; set; }
public long TotalBytesReceived { get; set; }
public double TotalSendSpeed { get; set; }
public double TotalReceiveSpeed { get; set; }
}
/// <summary>
/// 连接快照
/// </summary>
public class ConnectionSnapshot
{
public string Protocol { get; set; }
public string LocalIp { get; set; }
public int LocalPort { get; set; }
public string RemoteIp { get; set; }
public int RemotePort { get; set; }
public string RemoteDomain { get; set; }
public string State { get; set; }
/// <summary>
/// 方向
/// </summary>
public string Direction { get; set; }
public DateTime StartTime { get; set; }
public TimeSpan Duration { get; set; }
public long BytesSent { get; set; }
public long BytesReceived { get; set; }
public double CurrentSendSpeed { get; set; }
public double CurrentReceiveSpeed { get; set; }
public bool IsActive { get; set; }
}
/// <summary>
/// 全局网络统计
/// </summary>
public class GlobalNetworkStats
{
/// <summary>
/// 总软件数量
/// </summary>
public int TotalApplications { get; set; }
/// <summary>
/// 总连接数量
/// </summary>
public int TotalConnections { get; set; }
/// <summary>
/// 活跃连接数
/// </summary>
public int ActiveConnections { get; set; }
/// <summary>
/// 端口流量统计
/// </summary>
public List<PortTrafficInfo> PortTraffic { get; set; }
/// <summary>
/// IP 流量统计
/// </summary>
public List<IpTrafficInfo> IpTraffic { get; set; }
}
/// <summary>
/// 进程网络详情
/// </summary>
public class ProcessNetworkDetails
{
public int ProcessId { get; set; }
public string ProcessName { get; set; }
public ApplicationInfo ApplicationInfo { get; set; }
public List<ConnectionInfo> Connections { get; set; }
}
@@ -0,0 +1,424 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Net;
using Utils.ETW.Core;
using Utils.ETW.Models;
namespace Utils.ETW.Etw;
/// <summary>
/// 增强的ETW网络管理器 - 负责收集网络数据并更新到GlobalNetworkMonitor
/// </summary>
public class EnhancedEtwNetworkManager : IDisposable
{
private readonly EtwNetworkCapture _networkCapture = new();
private readonly CancellationTokenSource _cancellationTokenSource = new();
// 进程信息缓存
private readonly ConcurrentDictionary<int, ProcessInfo> _processCache = new();
// DNS反向查询任务队列
private readonly ConcurrentQueue<string> _dnsLookupQueue = new();
private bool _isRunning = false;
public EnhancedEtwNetworkManager()
{
SetupEventHandlers();
}
/// <summary>
/// 设置事件处理器
/// </summary>
private void SetupEventHandlers()
{
// TCP事件处理
_networkCapture.OnTcpConnectionEvent += HandleTcpEvent;
// UDP事件处理
_networkCapture.OnUdpPacketEvent += HandleUdpEvent;
// DNS事件处理
_networkCapture.OnDnsEvent += HandleDnsEvent;
// HTTP事件处理
_networkCapture.OnHttpEvent += HandleHttpEvent;
}
/// <summary>
/// 开始监控
/// </summary>
public void StartMonitoring()
{
if (_isRunning) return;
_isRunning = true;
// 启动ETW捕获
_networkCapture.StartCapture();
// 启动辅助任务
Task.Run(() => ProcessApplicationInfoAsync(_cancellationTokenSource.Token));
Task.Run(() => ProcessDnsLookupsAsync(_cancellationTokenSource.Token));
Task.Run(() => CleanupExpiredDataAsync(_cancellationTokenSource.Token));
Console.WriteLine("增强型网络监控已启动");
}
/// <summary>
/// 停止监控
/// </summary>
public void StopMonitoring()
{
if (!_isRunning) return;
_isRunning = false;
_cancellationTokenSource.Cancel();
_networkCapture.StopCapture();
Console.WriteLine("增强型网络监控已停止");
}
#region 事件处理方法
private void HandleTcpEvent(TcpConnectionEventData tcpEvent)
{
try
{
// 更新进程信息
UpdateProcessInfo(tcpEvent.ProcessId, tcpEvent.ProcessName, tcpEvent.ThreadId);
// 创建或更新网络模型
var networkModel = new NetworkModel
{
ConnectType = ProtocolType.TCP,
ProcessId = tcpEvent.ProcessId,
ThreadId = tcpEvent.ThreadId,
ProcessName = tcpEvent.ProcessName,
SourceIp = tcpEvent.SourceIp,
DestinationIp = tcpEvent.DestinationIp,
SourcePort = tcpEvent.SourcePort,
DestinationPort = tcpEvent.DestinationPort,
LastSeenTime = DateTime.Now,
RecordTime = tcpEvent.Timestamp,
Direction = tcpEvent.Direction,
IsPartialConnection = false,
State = ConnectionState.Connecting
};
// 根据事件类型处理
switch (tcpEvent.EventType)
{
case "TcpConnect":
networkModel.StartTime = tcpEvent.Timestamp;
networkModel.State = ConnectionState.Connecting;
break;
case "TcpDisconnect":
networkModel.EndTime = tcpEvent.Timestamp;
networkModel.State = ConnectionState.Disconnected;
break;
case "TcpSend":
networkModel.BytesSent = tcpEvent.DataLength;
networkModel.State = ConnectionState.Connected;
break;
case "TcpReceive":
networkModel.BytesReceived = tcpEvent.DataLength;
networkModel.State = ConnectionState.Connected;
break;
}
// 更新到全局监控器
GlobalNetworkMonitor.Instance.UpdateConnectionInfo(networkModel);
// 添加到DNS查询队列
if (!IsPrivateIp(tcpEvent.DestinationIp))
{
_dnsLookupQueue.Enqueue(tcpEvent.DestinationIp.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine($"处理TCP事件时出错: {ex.Message}");
}
}
private void HandleUdpEvent(UdpPacketEventData udpEvent)
{
try
{
// 更新进程信息
UpdateProcessInfo(udpEvent.ProcessId, udpEvent.ProcessName, udpEvent.ThreadId);
var networkModel = new NetworkModel
{
ConnectType = ProtocolType.UDP,
ProcessId = udpEvent.ProcessId,
ThreadId = udpEvent.ThreadId,
ProcessName = udpEvent.ProcessName,
SourceIp = udpEvent.SourceIp,
DestinationIp = udpEvent.DestinationIp,
SourcePort = udpEvent.SourcePort,
DestinationPort = udpEvent.DestinationPort,
StartTime = udpEvent.Timestamp,
LastSeenTime = DateTime.Now,
RecordTime = udpEvent.Timestamp,
Direction = udpEvent.Direction,
State = ConnectionState.Connected,
IsPartialConnection = false
};
if (udpEvent.EventType == "UdpSend")
{
networkModel.BytesSent = udpEvent.DataLength;
}
else if (udpEvent.EventType == "UdpReceive")
{
networkModel.BytesReceived = udpEvent.DataLength;
}
// 更新到全局监控器
GlobalNetworkMonitor.Instance.UpdateConnectionInfo(networkModel);
// 添加到DNS查询队列
if (!IsPrivateIp(udpEvent.DestinationIp))
{
_dnsLookupQueue.Enqueue(udpEvent.DestinationIp.ToString());
}
}
catch (Exception ex)
{
Console.WriteLine($"处理UDP事件时出错: {ex.Message}");
}
}
private void HandleDnsEvent(DnsEventData dnsEvent)
{
try
{
// 更新DNS缓存
if (!string.IsNullOrEmpty(dnsEvent.QueryName) && dnsEvent.ResolvedAddresses?.Count > 0)
{
foreach (var ip in dnsEvent.ResolvedAddresses)
{
GlobalNetworkMonitor.Instance.UpdateDnsInfo(ip, dnsEvent.QueryName, dnsEvent.QueryType);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"处理DNS事件时出错: {ex.Message}");
}
}
private void HandleHttpEvent(HttpEventData httpEvent)
{
try
{
// 可以从HTTP事件中提取更多应用层信息
Console.WriteLine($"[HTTP] {httpEvent.HttpMethod} {httpEvent.Url}");
}
catch (Exception ex)
{
Console.WriteLine($"处理HTTP事件时出错: {ex.Message}");
}
}
#endregion
#region 辅助方法
private void UpdateProcessInfo(int processId, string processName, int threadId)
{
try
{
// 更新进程网络信息
GlobalNetworkMonitor.Instance.UpdateProcessNetworkInfo(processId, processName, threadId);
// 如果进程信息不在缓存中,添加到缓存并获取详细信息
if (!_processCache.ContainsKey(processId))
{
_processCache.TryAdd(processId, new ProcessInfo
{
ProcessId = processId,
ProcessName = processName,
NeedsUpdate = true
});
}
}
catch (Exception ex)
{
Console.WriteLine($"更新进程信息时出错: {ex.Message}");
}
}
/// <summary>
/// 异步处理应用程序信息
/// </summary>
private async Task ProcessApplicationInfoAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
foreach (var kvp in _processCache.Where(p => p.Value.NeedsUpdate))
{
var processInfo = kvp.Value;
try
{
// 获取进程详细信息
using (var process = Process.GetProcessById(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(
processInfo.ProcessId,
appName,
appPath,
version
);
processInfo.NeedsUpdate = false;
}
}
}
catch (Exception ex)
{
// 进程可能已经退出
Console.WriteLine($"获取进程 {processInfo.ProcessId} 信息失败: {ex.Message}");
processInfo.NeedsUpdate = false;
}
}
await Task.Delay(1000, cancellationToken);
}
catch (Exception ex)
{
Console.WriteLine($"处理应用程序信息时出错: {ex.Message}");
}
}
}
/// <summary>
/// 异步处理DNS查询
/// </summary>
private async Task ProcessDnsLookupsAsync(CancellationToken cancellationToken)
{
var processedIps = new HashSet<string>();
while (!cancellationToken.IsCancellationRequested)
{
try
{
if (_dnsLookupQueue.TryDequeue(out var ip))
{
if (!processedIps.Contains(ip))
{
processedIps.Add(ip);
try
{
// 执行反向DNS查询
var hostEntry = await Dns.GetHostEntryAsync(ip);
if (!string.IsNullOrEmpty(hostEntry.HostName))
{
GlobalNetworkMonitor.Instance.UpdateDnsInfo(ip, hostEntry.HostName, "PTR");
}
}
catch
{
// DNS查询失败,忽略
}
}
}
else
{
await Task.Delay(100, cancellationToken);
}
}
catch (Exception ex)
{
Console.WriteLine($"处理DNS查询时出错: {ex.Message}");
}
}
}
/// <summary>
/// 定期清理过期数据
/// </summary>
private async Task CleanupExpiredDataAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
// 清理断开的连接
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
foreach (var app in snapshot.Applications)
{
foreach (var conn in app.Connections.Where(c => !c.IsActive && c.Duration > TimeSpan.FromMinutes(5)))
{
// 这里可以添加清理逻辑
Console.WriteLine($"清理过期连接: {app.ProcessName} - {conn.RemoteIp}:{conn.RemotePort}");
}
}
await Task.Delay(TimeSpan.FromMinutes(1), cancellationToken);
}
catch (Exception ex)
{
Console.WriteLine($"清理过期数据时出错: {ex.Message}");
}
}
}
private bool IsPrivateIp(IPAddress ip)
{
if (ip == null) return true;
var bytes = ip.GetAddressBytes();
// 10.0.0.0 - 10.255.255.255
if (bytes[0] == 10) return true;
// 172.16.0.0 - 172.31.255.255
if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) return true;
// 192.168.0.0 - 192.168.255.255
if (bytes[0] == 192 && bytes[1] == 168) return true;
// 127.0.0.0 - 127.255.255.255 (loopback)
if (bytes[0] == 127) return true;
return false;
}
#endregion
public void Dispose()
{
StopMonitoring();
_networkCapture?.Dispose();
_cancellationTokenSource?.Dispose();
}
/// <summary>
/// 进程信息缓存项
/// </summary>
private class ProcessInfo
{
public int ProcessId { get; set; }
public string ProcessName { get; set; }
public bool NeedsUpdate { get; set; }
}
}
@@ -0,0 +1,441 @@
using System.Collections.Concurrent;
using System.Net;
using Utils.ETW.Models;
namespace Utils.ETW.Etw;
/// <summary>
/// 全局网络监控数据管理器 - 单例模式
/// 负责收集、整合和管理所有网络监控数据
/// </summary>
public sealed class GlobalNetworkMonitor
{
private static readonly Lazy<GlobalNetworkMonitor> _instance = new(() => new GlobalNetworkMonitor());
public static GlobalNetworkMonitor Instance => _instance.Value;
/// <summary>
/// 读写锁,保证数据一致性
/// </summary>
private readonly ReaderWriterLockSlim _lock = new();
/// <summary>
/// 应用程序信息缓存 (ProcessId -> AppInfo)
/// </summary>
private readonly ConcurrentDictionary<int, ApplicationInfo> _applications = new();
/// <summary>
/// 进程信息缓存 (ProcessId -> ProcessInfo)
/// </summary>
private readonly ConcurrentDictionary<int, ProcessNetworkInfo> _processes = new();
/// <summary>
/// 连接信息缓存 (ConnectionKey -> ConnectionInfo)
/// </summary>
private readonly ConcurrentDictionary<string, ConnectionInfo> _connections = new();
/// <summary>
/// DNS解析缓存 (IP -> Domain)
/// </summary>
private readonly ConcurrentDictionary<string, DnsResolveInfo> _dnsCache = new();
/// <summary>
/// 端口流量统计
/// </summary>
private readonly ConcurrentDictionary<int, PortTrafficInfo> _portTraffic = new();
/// <summary>
/// IP流量统计
/// </summary>
private readonly ConcurrentDictionary<string, IpTrafficInfo> _ipTraffic = new();
/// <summary>
/// 统计信息更新时间
/// </summary>
private DateTime _lastUpdateTime = DateTime.Now;
private GlobalNetworkMonitor()
{
// 初始化
}
#region 数据更新方法 (只能由ETW模块调用)
/// <summary>
/// 更新应用程序信息
/// </summary>
public void UpdateApplicationInfo(int processId, string appName, string appPath, string version = null)
{
_lock.EnterWriteLock();
try
{
_applications.AddOrUpdate(processId,
new ApplicationInfo
{
ProcessId = processId,
ApplicationName = appName,
ApplicationPath = appPath,
Version = version,
FirstSeenTime = DateTime.Now,
LastUpdateTime = DateTime.Now
},
(key, existing) =>
{
existing.LastUpdateTime = DateTime.Now;
if (!string.IsNullOrEmpty(version))
existing.Version = version;
return existing;
});
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 更新进程网络信息
/// </summary>
public void UpdateProcessNetworkInfo(int processId, string processName, int threadId)
{
_lock.EnterWriteLock();
try
{
_processes.AddOrUpdate(processId,
new ProcessNetworkInfo
{
ProcessId = processId,
ProcessName = processName,
FirstSeenTime = DateTime.Now,
LastActiveTime = DateTime.Now,
ActiveConnections = new List<string>()
},
(key, existing) =>
{
existing.LastActiveTime = DateTime.Now;
return existing;
});
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 更新连接信息
/// </summary>
public void UpdateConnectionInfo(NetworkModel networkModel)
{
_lock.EnterWriteLock();
try
{
var connectionKey = networkModel.GetKey();
_connections.AddOrUpdate(connectionKey,
new ConnectionInfo
{
ConnectionKey = connectionKey,
ProcessId = networkModel.ProcessId,
Protocol = networkModel.ConnectType,
LocalEndpoint = new IPEndPoint(networkModel.SourceIp, networkModel.SourcePort),
RemoteEndpoint = new IPEndPoint(networkModel.DestinationIp, networkModel.DestinationPort),
State = networkModel.State,
Direction = networkModel.Direction,
StartTime = networkModel.StartTime ?? DateTime.Now,
LastActiveTime = networkModel.LastSeenTime,
BytesSent = networkModel.BytesSent,
BytesReceived = networkModel.BytesReceived,
IsActive = networkModel.State == ConnectionState.Connected
},
(key, existing) =>
{
existing.BytesSent = networkModel.BytesSent;
existing.BytesReceived = networkModel.BytesReceived;
existing.LastActiveTime = networkModel.LastSeenTime;
existing.State = networkModel.State;
existing.IsActive = networkModel.State == ConnectionState.Connected;
// 计算速率
var timeDiff = (networkModel.LastSeenTime - existing.LastSpeedCalculationTime).TotalSeconds;
if (timeDiff > 0)
{
existing.CurrentSendSpeed = (networkModel.BytesSent - existing.LastBytesSent) / timeDiff;
existing.CurrentReceiveSpeed =
(networkModel.BytesReceived - existing.LastBytesReceived) / timeDiff;
existing.LastBytesSent = networkModel.BytesSent;
existing.LastBytesReceived = networkModel.BytesReceived;
existing.LastSpeedCalculationTime = networkModel.LastSeenTime;
}
return existing;
});
// 更新进程的活跃连接列表
if (_processes.TryGetValue(networkModel.ProcessId, out var process))
{
if (!process.ActiveConnections.Contains(connectionKey))
{
process.ActiveConnections.Add(connectionKey);
}
}
// 更新端口流量统计
UpdatePortTraffic(networkModel.SourcePort, networkModel.BytesSent, networkModel.BytesReceived, true);
UpdatePortTraffic(networkModel.DestinationPort, networkModel.BytesSent, networkModel.BytesReceived, false);
// 更新IP流量统计
UpdateIpTraffic(networkModel.SourceIp.ToString(), networkModel.BytesSent, networkModel.BytesReceived, true);
UpdateIpTraffic(networkModel.DestinationIp.ToString(), networkModel.BytesSent, networkModel.BytesReceived,
false);
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 更新DNS解析信息
/// </summary>
public void UpdateDnsInfo(string ipAddress, string domainName, string queryType = "A")
{
_lock.EnterWriteLock();
try
{
_dnsCache.AddOrUpdate(ipAddress,
new DnsResolveInfo
{
IpAddress = ipAddress,
DomainName = domainName,
QueryType = queryType,
ResolveTime = DateTime.Now,
LastUsedTime = DateTime.Now
},
(key, existing) =>
{
existing.LastUsedTime = DateTime.Now;
if (!existing.AlternativeDomains.Contains(domainName))
{
existing.AlternativeDomains.Add(domainName);
}
return existing;
});
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 移除连接
/// </summary>
public void RemoveConnection(string connectionKey)
{
_lock.EnterWriteLock();
try
{
if (_connections.TryRemove(connectionKey, out var connection))
{
// 从进程的活跃连接列表中移除
if (_processes.TryGetValue(connection.ProcessId, out var process))
{
process.ActiveConnections.Remove(connectionKey);
}
}
}
finally
{
_lock.ExitWriteLock();
}
}
#endregion
#region 数据读取方法 (供其他模块调用)
/// <summary>
/// 获取完整的网络监控数据快照
/// </summary>
public NetworkMonitorSnapshot GetSnapshot()
{
_lock.EnterReadLock();
try
{
var snapshot = new NetworkMonitorSnapshot
{
SnapshotTime = DateTime.Now,
Applications = new List<ApplicationSnapshot>()
};
// 按应用程序组织数据
var appGroups = _processes.GroupBy(p => p.Value.ProcessId);
foreach (var group in appGroups)
{
var processId = group.Key;
var processInfo = _processes[processId];
// 获取应用程序信息
_applications.TryGetValue(processId, out var appInfo);
var appSnapshot = new ApplicationSnapshot
{
ProcessId = processId,
ApplicationName = appInfo?.ApplicationName ?? processInfo.ProcessName,
ApplicationPath = appInfo?.ApplicationPath ?? "Unknown",
Version = appInfo?.Version ?? "Unknown",
ProcessName = processInfo.ProcessName,
FirstSeenTime = processInfo.FirstSeenTime,
LastActiveTime = processInfo.LastActiveTime,
Connections = new List<ConnectionSnapshot>()
};
// 添加所有连接信息
foreach (var connKey in processInfo.ActiveConnections)
{
if (_connections.TryGetValue(connKey, out var conn))
{
var connSnapshot = new ConnectionSnapshot
{
Protocol = conn.Protocol.ToString(),
LocalPort = conn.LocalEndpoint.Port,
LocalIp = conn.LocalEndpoint.Address.ToString(),
RemoteIp = conn.RemoteEndpoint.Address.ToString(),
RemotePort = conn.RemoteEndpoint.Port,
RemoteDomain = GetDomainForIp(conn.RemoteEndpoint.Address.ToString()),
State = conn.State.ToString(),
Direction = conn.Direction.ToString(),
StartTime = conn.StartTime,
Duration = DateTime.Now - conn.StartTime,
BytesSent = conn.BytesSent,
BytesReceived = conn.BytesReceived,
CurrentSendSpeed = conn.CurrentSendSpeed,
CurrentReceiveSpeed = conn.CurrentReceiveSpeed,
IsActive = conn.IsActive
};
appSnapshot.Connections.Add(connSnapshot);
}
}
// 计算应用程序级别的统计
appSnapshot.TotalConnections = appSnapshot.Connections.Count;
appSnapshot.ActiveConnections = appSnapshot.Connections.Count(c => c.IsActive);
appSnapshot.TotalBytesSent = appSnapshot.Connections.Sum(c => c.BytesSent);
appSnapshot.TotalBytesReceived = appSnapshot.Connections.Sum(c => c.BytesReceived);
appSnapshot.TotalSendSpeed = appSnapshot.Connections.Sum(c => c.CurrentSendSpeed);
appSnapshot.TotalReceiveSpeed = appSnapshot.Connections.Sum(c => c.CurrentReceiveSpeed);
snapshot.Applications.Add(appSnapshot);
}
// 添加全局统计信息
snapshot.GlobalStats = new GlobalNetworkStats
{
TotalApplications = snapshot.Applications.Count,
TotalConnections = _connections.Count,
ActiveConnections = _connections.Count(c => c.Value.IsActive),
PortTraffic = _portTraffic.Values.ToList(),
IpTraffic = _ipTraffic.Values.OrderByDescending(i => i.TotalBytes).Take(100).ToList()
};
return snapshot;
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// 获取指定进程的网络信息
/// </summary>
public ProcessNetworkDetails GetProcessDetails(int processId)
{
_lock.EnterReadLock();
try
{
if (!_processes.TryGetValue(processId, out var processInfo))
return null;
_applications.TryGetValue(processId, out var appInfo);
var details = new ProcessNetworkDetails
{
ProcessId = processId,
ProcessName = processInfo.ProcessName,
ApplicationInfo = appInfo,
Connections = new List<ConnectionInfo>()
};
foreach (var connKey in processInfo.ActiveConnections)
{
if (_connections.TryGetValue(connKey, out var conn))
{
details.Connections.Add(conn);
}
}
return details;
}
finally
{
_lock.ExitReadLock();
}
}
#endregion
#region 私有辅助方法
private void UpdatePortTraffic(int port, long bytesSent, long bytesReceived, bool isLocal)
{
_portTraffic.AddOrUpdate(port,
new PortTrafficInfo
{
Port = port,
BytesSent = isLocal ? bytesSent : 0,
BytesReceived = isLocal ? 0 : bytesReceived,
LastUpdateTime = DateTime.Now
},
(key, existing) =>
{
if (isLocal)
existing.BytesSent = bytesSent;
else
existing.BytesReceived = bytesReceived;
existing.LastUpdateTime = DateTime.Now;
return existing;
});
}
private void UpdateIpTraffic(string ip, long bytesSent, long bytesReceived, bool isSource)
{
_ipTraffic.AddOrUpdate(ip,
new IpTrafficInfo
{
IpAddress = ip,
BytesSent = isSource ? bytesSent : 0,
BytesReceived = isSource ? 0 : bytesReceived,
LastUpdateTime = DateTime.Now
},
(key, existing) =>
{
if (isSource)
existing.BytesSent = bytesSent;
else
existing.BytesReceived = bytesReceived;
existing.LastUpdateTime = DateTime.Now;
return existing;
});
}
private string GetDomainForIp(string ip)
{
return _dnsCache.TryGetValue(ip, out var dnsInfo) ? dnsInfo.DomainName : null;
}
#endregion
}
@@ -0,0 +1,224 @@
using System.Runtime.CompilerServices;
using System.Text.Json;
using Utils.ETW.Core;
namespace Utils.ETW.Etw;
/// <summary>
/// 网络监控系统使用示例
/// </summary>
public class NetworkMonitorUsageExample
{
private EnhancedEtwNetworkManager _networkManager;
private CancellationTokenSource _cancellationTokenSource;
public void RunExample()
{
Console.WriteLine("启动网络监控系统...");
// 初始化网络管理器
_networkManager = new EnhancedEtwNetworkManager();
_cancellationTokenSource = new CancellationTokenSource();
try
{
// 启动监控
_networkManager.StartMonitoring();
// 启动定期读取任务
var readTask = Task.Run(() => ReadNetworkDataPeriodically(_cancellationTokenSource.Token));
// 启动WebSocket推送任务(示例)
// var websocketTask = Task.Run(() => SimulateWebSocketPush(_cancellationTokenSource.Token));
// Console.WriteLine("网络监控已启动,按任意键停止...");
// Console.ReadKey();
//
// // 停止监控
// _cancellationTokenSource.Cancel();
// await Task.WhenAll(readTask, websocketTask);
}
finally
{
// _networkManager?.Dispose();
// Console.WriteLine("网络监控已停止!!!!!!!!!!!!!11!!!!");
}
}
/// <summary>
/// 定期读取网络数据
/// </summary>
private async Task ReadNetworkDataPeriodically(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
// 获取网络监控快照
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
var serialize = JsonSerializer.Serialize(snapshot);
Console.WriteLine("=================================================");
Console.WriteLine(serialize);
Console.WriteLine("=================================================");
// 输出概要信息
Console.WriteLine($"\n========== 网络监控快照 {snapshot.SnapshotTime:yyyy-MM-dd HH:mm:ss} ==========");
Console.WriteLine($"活跃应用程序: {snapshot.GlobalStats.TotalApplications}");
Console.WriteLine(
$"总连接数: {snapshot.GlobalStats.TotalConnections} (活跃: {snapshot.GlobalStats.ActiveConnections})");
// 输出每个应用的详细信息
// foreach (var app in snapshot.Applications.OrderByDescending(a =>
// a.TotalSendSpeed + a.TotalReceiveSpeed))
// {
// Console.WriteLine($"\n应用程序: {app.ApplicationName} (PID: {app.ProcessId})");
// Console.WriteLine($" 路径: {app.ApplicationPath}");
// Console.WriteLine($" 版本: {app.Version}");
// Console.WriteLine($" 连接数: {app.ActiveConnections}/{app.TotalConnections}");
// Console.WriteLine(
// $" 总流量: 发送 {FormatBytes(app.TotalBytesSent)}, 接收 {FormatBytes(app.TotalBytesReceived)}");
// Console.WriteLine(
// $" 当前速度: ↑{FormatSpeed(app.TotalSendSpeed)} ↓{FormatSpeed(app.TotalReceiveSpeed)}");
//
// // 显示前5个活跃连接
// var topConnections = app.Connections
// .Where(c => c.IsActive)
// .OrderByDescending(c => c.CurrentSendSpeed + c.CurrentReceiveSpeed)
// .Take(5);
//
// foreach (var conn in topConnections)
// {
// Console.WriteLine(
// $" → {conn.Protocol} {conn.LocalPort} → {conn.RemoteIp}:{conn.RemotePort} " +
// $"({conn.RemoteDomain ?? "未解析"}) " +
// $"[{conn.State}] " +
// $"↑{FormatSpeed(conn.CurrentSendSpeed)} ↓{FormatSpeed(conn.CurrentReceiveSpeed)}");
// }
// }
//
// // 输出端口流量TOP 5
// Console.WriteLine("\n端口流量 TOP 5:");
// var topPorts = snapshot.GlobalStats.PortTraffic
// .OrderByDescending(p => p.TotalBytes)
// .Take(5);
//
// foreach (var port in topPorts)
// {
// Console.WriteLine($" 端口 {port.Port}: {FormatBytes(port.TotalBytes)} " +
// $"(发送: {FormatBytes(port.BytesSent)}, 接收: {FormatBytes(port.BytesReceived)})");
// }
//
// // 输出IP流量TOP 5
// Console.WriteLine("\nIP流量 TOP 5:");
// var topIps = snapshot.GlobalStats.IpTraffic.Take(5);
//
// foreach (var ip in topIps)
// {
// Console.WriteLine($" {ip.IpAddress}: {FormatBytes(ip.TotalBytes)} " +
// $"(发送: {FormatBytes(ip.BytesSent)}, 接收: {FormatBytes(ip.BytesReceived)})");
// }
await Task.Delay(5000, cancellationToken); // 每5秒更新一次
}
catch (Exception ex)
{
Console.WriteLine($"读取网络数据时出错: {ex.Message}");
}
}
}
/// <summary>
/// 模拟WebSocket推送
/// </summary>
// private async Task SimulateWebSocketPush(CancellationToken cancellationToken)
// {
// while (!cancellationToken.IsCancellationRequested)
// {
// try
// {
// // 获取数据快照
// var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
//
// // 构建要推送的数据(根据前端需求定制)
// var pushData = new
// {
// timestamp = snapshot.SnapshotTime,
// applications = snapshot.Applications.Select(app => new
// {
// processId = app.ProcessId,
// appName = app.ApplicationName,
// appPath = app.ApplicationPath,
// version = app.Version,
// connections = app.Connections.Select(conn => new
// {
// protocol = conn.Protocol,
// localPort = conn.LocalPort,
// remoteIp = conn.RemoteIp,
// remotePort = conn.RemotePort,
// remoteDomain = conn.RemoteDomain,
// state = conn.State,
// bytesSent = conn.BytesSent,
// bytesReceived = conn.BytesReceived,
// sendSpeed = conn.CurrentSendSpeed,
// receiveSpeed = conn.CurrentReceiveSpeed,
// duration = conn.Duration.TotalSeconds
// }),
// stats = new
// {
// totalConnections = app.TotalConnections,
// activeConnections = app.ActiveConnections,
// totalBytesSent = app.TotalBytesSent,
// totalBytesReceived = app.TotalBytesReceived,
// totalSendSpeed = app.TotalSendSpeed,
// totalReceiveSpeed = app.TotalReceiveSpeed
// }
// }),
// globalStats = new
// {
// totalApps = snapshot.GlobalStats.TotalApplications,
// totalConnections = snapshot.GlobalStats.TotalConnections,
// activeConnections = snapshot.GlobalStats.ActiveConnections
// }
// };
//
// // 序列化为JSON
// var json = JsonSerializer.Serialize(pushData);
//
// // 这里应该通过WebSocket发送数据
// // await websocketClient.SendAsync(json);
// Console.WriteLine($"\n[WebSocket模拟] 推送数据大小: {json.Length} 字节");
// Console.WriteLine(json);
// await Task.Delay(1000, cancellationToken); // 每秒推送一次
// }
// catch (Exception ex)
// {
// Console.WriteLine($"WebSocket推送时出错: {ex.Message}");
// }
// }
// }
/// <summary>
/// 格式化字节数
/// </summary>
private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB", "TB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
/// <summary>
/// 格式化速度
/// </summary>
private string FormatSpeed(double bytesPerSecond)
{
return FormatBytes((long)bytesPerSecond) + "/s";
}
}