A:增加窗口网速展示

This commit is contained in:
jimmy committed 2025-07-12 16:15:03 +08:00
1 parent d484c85abb
commit c1d9e2c068
28 files changed
+2107 -479

No files matched your search

@@ -1,16 +1,13 @@
using System.Collections.Concurrent;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Common;
using Common.Logger;
using Common.Net.WebSocketConn;
using Common.Utils;
using Infrastructure.Models;
using Infrastructure.utils;
using Utils.ETW.Etw;
namespace Shell;
namespace Application;
public class DispatchEngine
{
@@ -3,6 +3,7 @@ using System.Net;
using System.Text;
using System.Text.Json;
using System.Web;
using Common.Logger;
using Common.Utils;
using Fleck;
@@ -105,6 +106,7 @@ public class HttpServer
/// 便捷路由方法
/// </summary>
public void Get(string pattern, RequestHandler handler) => AddRoute(HttpMethod.GET, pattern, handler);
public void Post(string pattern, RequestHandler handler) => AddRoute(HttpMethod.POST, pattern, handler);
public void Put(string pattern, RequestHandler handler) => AddRoute(HttpMethod.PUT, pattern, handler);
public void Delete(string pattern, RequestHandler handler) => AddRoute(HttpMethod.DELETE, pattern, handler);
@@ -116,7 +118,7 @@ public class HttpServer
{
_listener.Start();
_isRunning = true;
Console.WriteLine($"HTTP Server started at {_prefix}");
Log.Info($"HTTP Server started at {_prefix}");
while (_isRunning && !cancellationToken.IsCancellationRequested)
{
@@ -135,7 +137,7 @@ public class HttpServer
}
catch (Exception ex)
{
Console.WriteLine($"Error accepting request: {ex.Message}");
Log.Info($"Error accepting request: {ex.Message}");
}
}
}
@@ -146,7 +148,7 @@ public class HttpServer
_isRunning = false;
_listener.Stop();
_listener.Close();
Console.WriteLine("HTTP Server stopped");
Log.Info("HTTP Server stopped");
}
// 处理请求
@@ -179,7 +181,7 @@ public class HttpServer
}
catch (Exception ex)
{
Console.WriteLine($"Request handling error: {ex}");
Log.Info($"Request handling error: {ex}");
await SendInternalServerError(listenerContext.Response, ex);
}
finally
@@ -286,7 +288,7 @@ public static class HttpListenerResponseExtensions
{
response.ContentType = "application/json; charset=utf-8";
var json = JsonHelper.ToJson(data);
var buffer = Encoding.UTF8.GetBytes(json);
response.ContentLength64 = buffer.Length;
await response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
@@ -315,7 +317,6 @@ public static class Middlewares
// CORS 中间件
public static async Task<bool> Cors(HttpContext context)
{
// 允许所有来源(生产环境应该指定具体域名)
string? origin = context.Request.Headers["Origin"];
context.Response.Headers.Add("Access-Control-Allow-Origin", !string.IsNullOrEmpty(origin) ? origin : "*");
@@ -324,7 +325,7 @@ public static class Middlewares
context.Response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH");
// 关键:允许的请求头(包括你的uuid头)
context.Response.Headers.Add("Access-Control-Allow-Headers",
context.Response.Headers.Add("Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With, uuid, Accept, Origin");
// 允许携带凭据(如果需要)
@@ -349,7 +350,7 @@ public static class Middlewares
public static async Task<bool> RequestLogging(HttpContext context)
{
var startTime = DateTime.UtcNow;
Console.WriteLine($"[{startTime:yyyy-MM-dd HH:mm:ss}] {context.Request.HttpMethod} {context.Request.Url}");
Log.Info($"[{startTime:yyyy-MM-dd HH:mm:ss}] {context.Request.HttpMethod} {context.Request.Url}");
// 继续处理
return await Task.FromResult(true);
@@ -142,6 +142,7 @@ public class WebSocketManager
{
gzip.Write(inputBytes, 0, inputBytes.Length);
}
return outputStream.ToArray();
}
@@ -243,7 +244,7 @@ public class WebSocketManager
}
else
{
Console.WriteLine("连接缺少userId参数");
Log.Info("连接缺少userId参数");
socket.Close();
}
}
@@ -268,7 +269,7 @@ public class WebSocketManager
}
catch (Exception ex)
{
Console.WriteLine($"解析userId时出错: {ex.Message}");
Log.Info($"解析userId时出错: {ex.Message}");
}
return null;
@@ -302,7 +303,7 @@ public class WebSocketManager
{
try
{
Console.WriteLine(DateTime.Now);
Log.Info($"{DateTime.Now}");
var commandMessage = JsonHelper.FromJson<CommandMessage>(message);
if (commandMessage != null && !string.IsNullOrEmpty(commandMessage.Command))
{
@@ -534,11 +535,11 @@ public static class WebSocketManagerUsageExample
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 ?? "未知"}");
Log.Info($"连接已关闭:");
Log.Info($" Socket ID: {args.SocketId}");
Log.Info($" UUID: {args.Uuid ?? "未知"}");
Log.Info($" 关闭时间: {args.ClosedAt}");
Log.Info($" 关闭原因: {args.Reason ?? "未知"}");
// 在这里可以执行清理逻辑,比如:
// - 清理用户相关的缓存数据
@@ -556,6 +557,6 @@ public static class WebSocketManagerUsageExample
private static void CleanupUserData(string uuid)
{
// 实现用户数据清理逻辑
Console.WriteLine($"清理用户 {uuid} 的相关数据");
Log.Info($"清理用户 {uuid} 的相关数据");
}
}
@@ -1,79 +1,9 @@
using NetVizor.Common.Utils;
using NUnit.Framework;
using System;
using System.Linq;
using System.Threading;
using Common.Utils;
namespace Common.Test
{
[TestFixture]
public class NetworkInfoUtilTest
{
[Test]
public void TestGetAllInterfaces()
{
TestContext.Progress.WriteLine("--- Network Interface List ---");
// 1. Get all network interface information
var interfaces = NetworkInfoUtil.GetAllInterfaces();
Assert.IsNotNull(interfaces);
Assert.IsTrue(interfaces.Count > 0, "No network interfaces found.");
foreach (var iface in interfaces)
{
TestContext.Progress.WriteLine($"Index: {iface.Index}, Alias: {iface.Alias}, Status: {iface.Status}");
TestContext.Progress.WriteLine($" Description: {iface.Description}");
TestContext.Progress.WriteLine($" MAC: {iface.MacAddress}, Type: {iface.Type}");
TestContext.Progress.WriteLine(
$" Bytes Sent: {iface.BytesSent}, Bytes Received: {iface.BytesReceived}\n");
}
}
[Test]
public void TestMonitorActiveInterfaceSpeed()
{
var interfaces = NetworkInfoUtil.GetAllInterfaces();
// 2. Select an active interface to monitor real-time speed
var activeInterface = interfaces.FirstOrDefault(i =>
i.Status == System.Net.NetworkInformation.OperationalStatus.Up
&& i.Type != System.Net.NetworkInformation.NetworkInterfaceType.Loopback
&& i.Type != System.Net.NetworkInformation.NetworkInterfaceType.Tunnel);
if (activeInterface == null)
{
Assert.Inconclusive("No active, non-loopback interface found to monitor. Test skipped.");
return; // Skip test if no suitable interface is found
}
TestContext.Progress.WriteLine($"--- Monitoring real-time speed for: {activeInterface.Alias} ---");
var speedMonitor = new NetworkSpeedMonitor(activeInterface);
// 3. Periodically update and display the network speed
TestContext.Progress.WriteLine("Monitoring for 5 seconds...");
for (int i = 0; i < 5; i++)
{
Thread.Sleep(1000); // Update every second
speedMonitor.Update();
string downSpeed = FormatSpeed(speedMonitor.DownloadSpeedBps);
string upSpeed = FormatSpeed(speedMonitor.UploadSpeedBps);
TestContext.Progress.WriteLine(
$"Time: {DateTime.Now:HH:mm:ss} | Download: {downSpeed} | Upload: {upSpeed}");
}
Assert.IsTrue(speedMonitor.DownloadSpeedBps >= 0);
Assert.IsTrue(speedMonitor.UploadSpeedBps >= 0);
}
private static string FormatSpeed(double bytesPerSecond)
{
if (bytesPerSecond < 1024)
return $"{bytesPerSecond:F2} B/s";
if (bytesPerSecond < 1024 * 1024)
return $"{bytesPerSecond / 1024:F2} KB/s";
return $"{bytesPerSecond / (1024 * 1024):F2} MB/s";
}
}
}
@@ -1,6 +1,6 @@
using Serilog;
using Common.Logger;
namespace Common.FunExpand;
namespace Common.ExpandFun;
public static class StringExpand
{
@@ -61,4 +61,4 @@ public static class StringExpand
return null;
}
}
}
}
@@ -0,0 +1,366 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Threading;
using Common.Logger;
namespace Common.Utils
{
/// <summary>
/// 基础网络监控帮助类 - 专注于网速计算
/// </summary>
public static class BasicNetworkMonitor
{
#region 数据模型
/// <summary>
/// 基础网络接口信息
/// </summary>
public class BasicNetworkInterface
{
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Id { get; set; } = string.Empty;
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
public bool IsConnected { get; set; }
public NetworkInterfaceType Type { get; set; }
public string TypeDescription { get; set; } = string.Empty;
public override string ToString()
{
return Name;
}
}
/// <summary>
/// 网络统计快照
/// </summary>
private class NetworkSnapshot
{
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
public DateTime Timestamp { get; set; }
}
#endregion
#region 私有字段
// 使用线程安全的字典存储历史统计数据
private static readonly ConcurrentDictionary<string, NetworkSnapshot> PreviousStats = new();
private static readonly object LockObject = new();
private static volatile bool _isInitialized = false;
#endregion
#region 公共方法
/// <summary>
/// 获取所有网络接口
/// </summary>
/// <param name="includeLoopback">是否包含环回接口</param>
/// <returns>网络接口列表</returns>
public static List<BasicNetworkInterface> GetNetworkInterfaces(bool includeLoopback = false)
{
var interfaces = new List<BasicNetworkInterface>();
try
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in networkInterfaces)
{
// 根据参数决定是否跳过环回接口
if (!includeLoopback && ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
{
continue;
}
var basicInterface = CreateBasicInterface(ni);
if (basicInterface != null)
{
interfaces.Add(basicInterface);
}
}
}
catch (Exception ex)
{
Log.Error4Ctx($"获取网络接口时发生错误: {ex.Message}");
}
return interfaces;
}
/// <summary>
/// 根据接口名称计算网速
/// </summary>
/// <param name="interfaceName">接口名称</param>
/// <returns>网速信息</returns>
public static NetworkSpeed CalculateSpeedByName(string interfaceName)
{
if (string.IsNullOrWhiteSpace(interfaceName))
{
Log.Warning("接口名称不能为空");
return new NetworkSpeed();
}
var interfaces = GetNetworkInterfaces();
var targetInterface = interfaces.FirstOrDefault(i =>
string.Equals(i.Name, interfaceName, StringComparison.OrdinalIgnoreCase) ||
string.Equals(i.Id, interfaceName, StringComparison.OrdinalIgnoreCase));
if (targetInterface == null)
{
Log.Warning($"未找到接口: {interfaceName}");
return new NetworkSpeed();
}
return CalculateSpeed(targetInterface);
}
/// <summary>
/// 根据接口ID计算网速
/// </summary>
/// <param name="interfaceId">接口ID</param>
/// <returns>网速信息</returns>
public static NetworkSpeed CalculateSpeedById(string interfaceId)
{
return CalculateSpeedByName(interfaceId);
}
/// <summary>
/// 计算所有网络接口的总网速
/// </summary>
/// <returns>总网速信息</returns>
public static NetworkSpeed CalculateTotalSpeed()
{
var currentInterfaces = GetNetworkInterfaces();
var now = DateTime.Now;
var totalSpeed = new NetworkSpeed();
// 确保初始化
EnsureInitialized(currentInterfaces, now);
foreach (var currentInterface in currentInterfaces)
{
var speed = CalculateSpeed(currentInterface, now);
totalSpeed.DownloadSpeed += speed.DownloadSpeed;
totalSpeed.UploadSpeed += speed.UploadSpeed;
}
Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
return totalSpeed;
}
/// <summary>
/// 重置统计数据
/// </summary>
public static void ResetStatistics()
{
lock (LockObject)
{
Log.Info("重置网络统计数据");
PreviousStats.Clear();
_isInitialized = false;
}
}
/// <summary>
/// 获取接口的历史统计数据
/// </summary>
/// <param name="interfaceId">接口ID</param>
/// <returns>是否存在历史数据</returns>
public static bool HasHistoricalData(string interfaceId)
{
return !string.IsNullOrEmpty(interfaceId) && PreviousStats.ContainsKey(interfaceId);
}
/// <summary>
/// 获取已连接的网络接口
/// </summary>
/// <returns>已连接的网络接口列表</returns>
public static List<BasicNetworkInterface> GetConnectedNetworkInterfaces()
{
return GetNetworkInterfaces()
.Where(i => i.IsConnected)
.ToList();
}
#endregion
#region 私有方法
/// <summary>
/// 创建基础网络接口信息
/// </summary>
/// <param name="ni">网络接口</param>
/// <returns>基础网络接口信息</returns>
private static BasicNetworkInterface CreateBasicInterface(NetworkInterface ni)
{
try
{
// 获取IPv4统计信息
var stats = ni.GetIPv4Statistics();
return new BasicNetworkInterface
{
Name = ni.Name,
Description = ni.Description,
Id = ni.Id,
BytesReceived = stats.BytesReceived,
BytesSent = stats.BytesSent,
IsConnected = ni.OperationalStatus == OperationalStatus.Up,
Type = ni.NetworkInterfaceType,
TypeDescription = NetworkHelper.GetInterfaceTypeDescription(ni.NetworkInterfaceType)
};
}
catch (Exception ex)
{
Log.Warning($"创建接口 {ni.Name} 基础信息时发生错误: {ex.Message}");
return null;
}
}
/// <summary>
/// 计算指定接口的网速
/// </summary>
/// <param name="currentInterface">当前接口信息</param>
/// <param name="now">当前时间(可选)</param>
/// <returns>网速信息</returns>
private static NetworkSpeed CalculateSpeed(BasicNetworkInterface currentInterface, DateTime? now = null)
{
if (currentInterface == null)
{
return new NetworkSpeed();
}
var timestamp = now ?? DateTime.Now;
var key = currentInterface.Id;
var speed = new NetworkSpeed();
Log.Debug($"计算接口 {currentInterface.Name} 的网速...");
// 确保初始化
if (!_isInitialized)
{
EnsureInitialized(new[] { currentInterface }, timestamp);
return speed;
}
// 获取或创建前一次的快照
var currentSnapshot = new NetworkSnapshot
{
BytesReceived = currentInterface.BytesReceived,
BytesSent = currentInterface.BytesSent,
Timestamp = timestamp
};
if (PreviousStats.TryGetValue(key, out var previousSnapshot))
{
var timeDiff = (timestamp - previousSnapshot.Timestamp).TotalSeconds;
if (NetworkHelper.IsValidTimeInterval(timeDiff))
{
// 计算速度
speed.DownloadSpeed = NetworkHelper.CalculateSpeed(
currentSnapshot.BytesReceived,
previousSnapshot.BytesReceived,
timeDiff);
speed.UploadSpeed = NetworkHelper.CalculateSpeed(
currentSnapshot.BytesSent,
previousSnapshot.BytesSent,
timeDiff);
Log.Debug(
$"接口 {currentInterface.Name} - 下载: {speed.DownloadSpeedText}, 上传: {speed.UploadSpeedText}");
}
else
{
Log.Debug($"时间间隔过短 ({timeDiff:F2}秒),跳过速度计算");
}
}
else
{
Log.Debug($"接口 {currentInterface.Name} 首次记录数据");
}
// 更新快照
PreviousStats.AddOrUpdate(key, currentSnapshot, (k, v) => currentSnapshot);
return speed;
}
/// <summary>
/// 确保系统已初始化
/// </summary>
/// <param name="interfaces">接口列表</param>
/// <param name="timestamp">时间戳</param>
private static void EnsureInitialized(IEnumerable<BasicNetworkInterface> interfaces, DateTime timestamp)
{
if (_isInitialized)
{
return;
}
lock (LockObject)
{
if (_isInitialized)
{
return;
}
Log.Info("初始化网络监控统计数据");
foreach (var iface in interfaces)
{
if (iface != null)
{
PreviousStats.TryAdd(iface.Id, new NetworkSnapshot
{
BytesReceived = iface.BytesReceived,
BytesSent = iface.BytesSent,
Timestamp = timestamp
});
}
}
_isInitialized = true;
Log.Info($"已初始化 {PreviousStats.Count} 个网络接口的统计数据");
}
}
/// <summary>
/// 清理过期的统计数据
/// </summary>
/// <param name="maxAge">最大保留时间</param>
public static void CleanupOldStatistics(TimeSpan maxAge)
{
var cutoffTime = DateTime.Now - maxAge;
var expiredKeys = new List<string>();
foreach (var kvp in PreviousStats)
{
if (kvp.Value.Timestamp < cutoffTime)
{
expiredKeys.Add(kvp.Key);
}
}
foreach (var key in expiredKeys)
{
PreviousStats.TryRemove(key, out _);
}
if (expiredKeys.Count > 0)
{
Log.Info($"清理了 {expiredKeys.Count} 个过期的网络统计记录");
}
}
#endregion
}
}
@@ -0,0 +1,420 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Common.Logger;
namespace Common.Utils
{
/// <summary>
/// 增强的网络监控帮助类 - 获取详细的网络信息
/// </summary>
public static class EnhancedNetworkMonitor
{
#region 数据模型
/// <summary>
/// 详细的网络接口信息
/// </summary>
public class DetailedNetworkInterface
{
// 基本信息
public string Name { get; set; } = string.Empty;
public string Description { get; set; } = string.Empty;
public string Id { get; set; } = string.Empty;
public bool IsConnected { get; set; }
public NetworkInterfaceType Type { get; set; }
public string TypeDescription { get; set; } = string.Empty;
// 物理信息
public string PhysicalAddress { get; set; } = string.Empty;
public long Speed { get; set; }
public string SpeedText { get; set; } = string.Empty;
// IP配置
public List<string> IPAddresses { get; set; } = new();
public List<string> SubnetMasks { get; set; } = new();
public List<string> Gateways { get; set; } = new();
public List<string> DnsServers { get; set; } = new();
public List<string> IPv6Addresses { get; set; } = new();
// 统计信息
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
public long PacketsReceived { get; set; }
public long PacketsSent { get; set; }
public long ErrorsReceived { get; set; }
public long ErrorsSent { get; set; }
public override string ToString()
{
return $"{Name} - {Description}";
}
}
#endregion
#region 公共方法
/// <summary>
/// 获取所有网络接口的详细信息
/// </summary>
/// <param name="includeLoopback">是否包含环回接口</param>
/// <returns>网络接口列表</returns>
public static List<DetailedNetworkInterface> GetDetailedNetworkInterfaces(bool includeLoopback = false)
{
var interfaces = new List<DetailedNetworkInterface>();
try
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in networkInterfaces)
{
// 根据参数决定是否跳过环回接口
if (!includeLoopback && ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
{
continue;
}
var detailedInterface = CreateDetailedInterface(ni);
if (detailedInterface != null)
{
interfaces.Add(detailedInterface);
}
}
}
catch (Exception ex)
{
Log.Error4Ctx($"获取网络接口详细信息时发生错误: {ex.Message}");
}
return interfaces;
}
/// <summary>
/// 获取已连接的网络接口
/// </summary>
/// <returns>已连接的网络接口列表</returns>
public static List<DetailedNetworkInterface> GetConnectedNetworkInterfaces()
{
return GetDetailedNetworkInterfaces()
.Where(i => i.IsConnected)
.ToList();
}
/// <summary>
/// 根据名称获取网络接口
/// </summary>
/// <param name="name">接口名称</param>
/// <returns>网络接口信息,未找到则返回null</returns>
public static DetailedNetworkInterface GetNetworkInterfaceByName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return null;
}
return GetDetailedNetworkInterfaces()
.FirstOrDefault(i => string.Equals(i.Name, name, StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 获取外网IP地址
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>外网IP信息</returns>
public static async Task<ExternalIPInfo> GetExternalIPAsync(CancellationToken cancellationToken = default)
{
return await NetworkHelper.GetExternalIPAsync(cancellationToken);
}
/// <summary>
/// 获取当前主要网络接口的详细信息
/// </summary>
/// <returns>主要网络接口信息,如果没有则返回null</returns>
public static DetailedNetworkInterface GetPrimaryNetworkInterface()
{
var connectedInterfaces = GetConnectedNetworkInterfaces();
// 优先选择有网关的以太网接口
var primaryInterface = connectedInterfaces
.Where(i => i.Type == NetworkInterfaceType.Ethernet && i.Gateways.Any())
.FirstOrDefault();
// 如果没有以太网,选择有网关的Wi-Fi接口
if (primaryInterface == null)
{
primaryInterface = connectedInterfaces
.Where(i => i.Type == NetworkInterfaceType.Wireless80211 && i.Gateways.Any())
.FirstOrDefault();
}
// 如果还没有,选择任何有IP地址的接口
if (primaryInterface == null)
{
primaryInterface = connectedInterfaces
.Where(i => i.IPAddresses.Any())
.FirstOrDefault();
}
return primaryInterface;
}
/// <summary>
/// 获取完整的网络状态报告
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>网络状态报告</returns>
public static async Task<string> GetNetworkStatusReportAsync(CancellationToken cancellationToken = default)
{
var sb = new StringBuilder();
try
{
var interfaces = GetConnectedNetworkInterfaces();
var externalIP = await GetExternalIPAsync(cancellationToken);
var uptime = NetworkHelper.GetSystemUptime();
// 报告头部
sb.AppendLine("=== 网络状态详细报告 ===");
sb.AppendLine($"报告生成时间: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
sb.AppendLine($"系统运行时间: {NetworkHelper.FormatUptime(uptime)}");
sb.AppendLine($"外网IPv4地址: {externalIP.IPv4}");
sb.AppendLine($"外网IPv6地址: {externalIP.IPv6}");
sb.AppendLine($"活跃网络接口数: {interfaces.Count}");
sb.AppendLine();
// 接口详情
foreach (var iface in interfaces)
{
AppendInterfaceInfo(sb, iface);
}
// 统计汇总
AppendNetworkSummary(sb, interfaces);
}
catch (Exception ex)
{
Log.Error4Ctx($"生成网络状态报告时发生错误: {ex.Message}");
sb.AppendLine($"生成报告时发生错误: {ex.Message}");
}
return sb.ToString();
}
#endregion
#region 私有方法
/// <summary>
/// 创建详细的网络接口信息
/// </summary>
/// <param name="ni">网络接口</param>
/// <returns>详细网络接口信息</returns>
private static DetailedNetworkInterface CreateDetailedInterface(NetworkInterface ni)
{
try
{
var detailedInterface = new DetailedNetworkInterface
{
// 基本信息
Name = ni.Name,
Description = ni.Description,
Id = ni.Id,
IsConnected = ni.OperationalStatus == OperationalStatus.Up,
Type = ni.NetworkInterfaceType,
TypeDescription = NetworkHelper.GetInterfaceTypeDescription(ni.NetworkInterfaceType),
// 物理信息
PhysicalAddress = NetworkHelper.FormatMacAddress(ni.GetPhysicalAddress()),
Speed = ni.Speed,
SpeedText = NetworkHelper.FormatInterfaceSpeed(ni.Speed)
};
// 获取统计信息
PopulateStatistics(detailedInterface, ni);
// 获取IP配置信息
PopulateIPConfiguration(detailedInterface, ni);
return detailedInterface;
}
catch (Exception ex)
{
Log.Warning($"创建接口 {ni.Name} 的详细信息时发生错误: {ex.Message}");
return null;
}
}
/// <summary>
/// 填充统计信息
/// </summary>
/// <param name="detailedInterface">详细接口信息</param>
/// <param name="ni">网络接口</param>
private static void PopulateStatistics(DetailedNetworkInterface detailedInterface, NetworkInterface ni)
{
try
{
var stats = ni.GetIPv4Statistics();
detailedInterface.BytesReceived = stats.BytesReceived;
detailedInterface.BytesSent = stats.BytesSent;
detailedInterface.PacketsReceived = stats.UnicastPacketsReceived;
detailedInterface.PacketsSent = stats.UnicastPacketsSent;
detailedInterface.ErrorsReceived = stats.IncomingPacketsWithErrors;
detailedInterface.ErrorsSent = stats.OutgoingPacketsWithErrors;
}
catch (Exception ex)
{
Log.Warning($"获取接口 {ni.Name} 统计信息时发生错误: {ex.Message}");
}
}
/// <summary>
/// 填充IP配置信息
/// </summary>
/// <param name="detailedInterface">详细接口信息</param>
/// <param name="ni">网络接口</param>
private static void PopulateIPConfiguration(DetailedNetworkInterface detailedInterface, NetworkInterface ni)
{
try
{
var ipProps = ni.GetIPProperties();
// 处理单播地址
foreach (var unicast in ipProps.UnicastAddresses)
{
switch (unicast.Address.AddressFamily)
{
case AddressFamily.InterNetwork:
detailedInterface.IPAddresses.Add(unicast.Address.ToString());
var mask = NetworkHelper.CalculateSubnetMask(unicast);
if (!string.IsNullOrEmpty(mask))
{
detailedInterface.SubnetMasks.Add(mask);
}
break;
case AddressFamily.InterNetworkV6:
detailedInterface.IPv6Addresses.Add(unicast.Address.ToString());
break;
}
}
// 处理网关
foreach (var gateway in ipProps.GatewayAddresses)
{
if (gateway.Address.AddressFamily == AddressFamily.InterNetwork)
{
detailedInterface.Gateways.Add(gateway.Address.ToString());
}
}
// 处理DNS服务器
foreach (var dns in ipProps.DnsAddresses)
{
if (dns.AddressFamily == AddressFamily.InterNetwork)
{
detailedInterface.DnsServers.Add(dns.ToString());
}
}
}
catch (Exception ex)
{
Log.Warning($"获取接口 {ni.Name} IP配置时发生错误: {ex.Message}");
}
}
/// <summary>
/// 添加接口信息到报告
/// </summary>
/// <param name="sb">字符串构建器</param>
/// <param name="iface">接口信息</param>
private static void AppendInterfaceInfo(StringBuilder sb, DetailedNetworkInterface iface)
{
sb.AppendLine($"接口名称: {iface.Name}");
sb.AppendLine($"接口描述: {iface.Description}");
sb.AppendLine($"连接类型: {iface.TypeDescription}");
sb.AppendLine($"接口速度: {iface.SpeedText}");
sb.AppendLine($"物理地址: {iface.PhysicalAddress}");
sb.AppendLine($"连接状态: {(iface.IsConnected ? "已连接" : "未连接")}");
if (iface.IPAddresses.Any())
{
sb.AppendLine($"IPv4地址: {string.Join(", ", iface.IPAddresses)}");
}
if (iface.SubnetMasks.Any())
{
sb.AppendLine($"子网掩码: {string.Join(", ", iface.SubnetMasks)}");
}
if (iface.Gateways.Any())
{
sb.AppendLine($"默认网关: {string.Join(", ", iface.Gateways)}");
}
if (iface.DnsServers.Any())
{
sb.AppendLine($"DNS服务器: {string.Join(", ", iface.DnsServers)}");
}
if (iface.IPv6Addresses.Any())
{
sb.AppendLine($"IPv6地址: {string.Join(", ", iface.IPv6Addresses)}");
}
sb.AppendLine($"已接收: {NetworkHelper.FormatBytes(iface.BytesReceived)} ({iface.PacketsReceived:N0} 包)");
sb.AppendLine($"已发送: {NetworkHelper.FormatBytes(iface.BytesSent)} ({iface.PacketsSent:N0} 包)");
if (iface.ErrorsReceived > 0 || iface.ErrorsSent > 0)
{
sb.AppendLine($"错误统计: 接收错误 {iface.ErrorsReceived:N0}, 发送错误 {iface.ErrorsSent:N0}");
}
sb.AppendLine();
}
/// <summary>
/// 添加网络汇总信息
/// </summary>
/// <param name="sb">字符串构建器</param>
/// <param name="interfaces">接口列表</param>
private static void AppendNetworkSummary(StringBuilder sb, List<DetailedNetworkInterface> interfaces)
{
if (!interfaces.Any())
{
return;
}
sb.AppendLine("=== 网络统计汇总 ===");
var totalBytesReceived = interfaces.Sum(i => i.BytesReceived);
var totalBytesSent = interfaces.Sum(i => i.BytesSent);
var totalPacketsReceived = interfaces.Sum(i => i.PacketsReceived);
var totalPacketsSent = interfaces.Sum(i => i.PacketsSent);
var totalErrors = interfaces.Sum(i => i.ErrorsReceived + i.ErrorsSent);
sb.AppendLine($"总接收流量: {NetworkHelper.FormatBytes(totalBytesReceived)}");
sb.AppendLine($"总发送流量: {NetworkHelper.FormatBytes(totalBytesSent)}");
sb.AppendLine($"总数据包: 接收 {totalPacketsReceived:N0}, 发送 {totalPacketsSent:N0}");
if (totalErrors > 0)
{
sb.AppendLine($"总错误数: {totalErrors:N0}");
}
var ethernetCount = interfaces.Count(i => i.Type == NetworkInterfaceType.Ethernet);
var wifiCount = interfaces.Count(i => i.Type == NetworkInterfaceType.Wireless80211);
sb.AppendLine(
$"接口类型分布: 以太网 {ethernetCount}, Wi-Fi {wifiCount}, 其他 {interfaces.Count - ethernetCount - wifiCount}");
}
#endregion
}
}
@@ -0,0 +1,422 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Common.Logger;
namespace Common.Utils
{
/// <summary>
/// 网络工具公共类 - 提供格式化、验证等公共功能
/// </summary>
public static class NetworkHelper
{
#region 常量定义
private const long MAX_REASONABLE_SPEED = 1_000_000_000; // 1GB/s 最大合理速度
private const double MIN_TIME_INTERVAL = 0.5; // 最小时间间隔(秒)
private const int MAC_ADDRESS_LENGTH = 12;
private const int IPV4_PREFIX_MAX = 32;
private const int IPV6_PREFIX_MAX = 128;
#endregion
#region 格式化方法
/// <summary>
/// 格式化网速显示
/// </summary>
/// <param name="bytesPerSecond">每秒字节数</param>
/// <returns>格式化后的速度字符串</returns>
public static string FormatSpeed(double bytesPerSecond)
{
if (!IsValidSpeed(bytesPerSecond))
{
return "0.00 B/s";
}
var units = new[] { "B/s", "KB/s", "MB/s", "GB/s", "TB/s" };
var unitIndex = 0;
var speed = bytesPerSecond;
while (speed >= 1024 && unitIndex < units.Length - 1)
{
speed /= 1024;
unitIndex++;
}
return $"{speed:0.00} {units[unitIndex]}";
}
/// <summary>
/// 格式化接口速度显示
/// </summary>
/// <param name="bitsPerSecond">每秒比特数</param>
/// <returns>格式化后的速度字符串</returns>
public static string FormatInterfaceSpeed(long bitsPerSecond)
{
if (bitsPerSecond <= 0)
{
return "未知";
}
var units = new[] { "bps", "Kbps", "Mbps", "Gbps", "Tbps" };
var unitIndex = 0;
var speed = (double)bitsPerSecond;
while (speed >= 1000 && unitIndex < units.Length - 1)
{
speed /= 1000;
unitIndex++;
}
return $"{speed:0.##} {units[unitIndex]}";
}
/// <summary>
/// 格式化字节数显示
/// </summary>
/// <param name="bytes">字节数</param>
/// <returns>格式化后的字节数字符串</returns>
public static string FormatBytes(long bytes)
{
if (bytes < 0)
{
return "0 B";
}
var units = new[] { "B", "KB", "MB", "GB", "TB", "PB" };
var unitIndex = 0;
var size = (double)bytes;
while (size >= 1024 && unitIndex < units.Length - 1)
{
size /= 1024;
unitIndex++;
}
return $"{size:0.##} {units[unitIndex]}";
}
/// <summary>
/// 格式化MAC地址
/// </summary>
/// <param name="physicalAddress">物理地址对象</param>
/// <param name="separator">分隔符,默认为"-"</param>
/// <returns>格式化后的MAC地址</returns>
public static string FormatMacAddress(PhysicalAddress physicalAddress, string separator = "-")
{
if (physicalAddress == null)
{
return string.Empty;
}
var address = physicalAddress.ToString();
if (string.IsNullOrEmpty(address) || address.Length != MAC_ADDRESS_LENGTH)
{
return address;
}
return string.Join(separator,
Enumerable.Range(0, 6)
.Select(i => address.Substring(i * 2, 2))
.ToArray());
}
/// <summary>
/// 格式化系统运行时间
/// </summary>
/// <param name="uptime">运行时间</param>
/// <returns>格式化后的运行时间字符串</returns>
public static string FormatUptime(TimeSpan uptime)
{
if (uptime.TotalSeconds < 0)
{
return "0秒";
}
var parts = new List<string>();
if (uptime.Days > 0)
parts.Add($"{uptime.Days}天");
if (uptime.Hours > 0)
parts.Add($"{uptime.Hours}小时");
if (uptime.Minutes > 0)
parts.Add($"{uptime.Minutes}分");
if (uptime.Seconds > 0 || parts.Count == 0)
parts.Add($"{uptime.Seconds}秒");
return string.Join("", parts);
}
#endregion
#region 验证方法
/// <summary>
/// 验证网速是否有效
/// </summary>
/// <param name="speed">网速值</param>
/// <returns>是否有效</returns>
public static bool IsValidSpeed(double speed)
{
return speed >= 0 &&
!double.IsNaN(speed) &&
!double.IsInfinity(speed) &&
speed < MAX_REASONABLE_SPEED;
}
/// <summary>
/// 验证时间间隔是否足够
/// </summary>
/// <param name="timeInterval">时间间隔(秒)</param>
/// <returns>是否足够</returns>
public static bool IsValidTimeInterval(double timeInterval)
{
return timeInterval >= MIN_TIME_INTERVAL;
}
/// <summary>
/// 验证字节数变化是否合理
/// </summary>
/// <param name="bytesChange">字节数变化</param>
/// <returns>是否合理</returns>
public static bool IsValidBytesChange(long bytesChange)
{
return bytesChange >= 0 && bytesChange < MAX_REASONABLE_SPEED;
}
#endregion
#region 计算方法
/// <summary>
/// 计算网速
/// </summary>
/// <param name="currentBytes">当前字节数</param>
/// <param name="previousBytes">之前字节数</param>
/// <param name="timeInterval">时间间隔(秒)</param>
/// <returns>网速(字节/秒)</returns>
public static double CalculateSpeed(long currentBytes, long previousBytes, double timeInterval)
{
if (!IsValidTimeInterval(timeInterval))
{
return 0;
}
var bytesChange = currentBytes - previousBytes;
if (!IsValidBytesChange(bytesChange))
{
return 0;
}
return bytesChange / timeInterval;
}
/// <summary>
/// 计算子网掩码
/// </summary>
/// <param name="unicast">单播地址信息</param>
/// <returns>子网掩码字符串</returns>
public static string CalculateSubnetMask(UnicastIPAddressInformation unicast)
{
if (unicast == null)
{
return string.Empty;
}
try
{
// 优先使用IPv4Mask
if (unicast.IPv4Mask != null)
{
return unicast.IPv4Mask.ToString();
}
// 通过前缀长度计算
var prefixLength = unicast.PrefixLength;
if (prefixLength > 0 && prefixLength <= IPV4_PREFIX_MAX)
{
var mask = (uint)(0xFFFFFFFF << (IPV4_PREFIX_MAX - prefixLength));
return new IPAddress(new byte[]
{
(byte)(mask >> 24),
(byte)(mask >> 16),
(byte)(mask >> 8),
(byte)mask
}).ToString();
}
}
catch (Exception ex)
{
Log.Debug($"计算子网掩码时发生错误: {ex.Message}");
}
return string.Empty;
}
#endregion
#region 获取方法
/// <summary>
/// 获取网络接口类型描述
/// </summary>
/// <param name="type">接口类型</param>
/// <returns>类型描述</returns>
public static string GetInterfaceTypeDescription(NetworkInterfaceType type)
{
return type switch
{
NetworkInterfaceType.Ethernet => "以太网",
NetworkInterfaceType.Wireless80211 => "Wi-Fi",
NetworkInterfaceType.Loopback => "环回接口",
NetworkInterfaceType.Ppp => "PPP",
NetworkInterfaceType.Tunnel => "隧道",
NetworkInterfaceType.Slip => "SLIP",
NetworkInterfaceType.TokenRing => "令牌环",
NetworkInterfaceType.Fddi => "FDDI",
NetworkInterfaceType.BasicIsdn => "基本ISDN",
NetworkInterfaceType.PrimaryIsdn => "主要ISDN",
NetworkInterfaceType.GenericModem => "通用调制解调器",
NetworkInterfaceType.FastEthernetT => "快速以太网T",
NetworkInterfaceType.Isdn => "ISDN",
NetworkInterfaceType.FastEthernetFx => "快速以太网FX",
NetworkInterfaceType.Wman => "无线城域网",
NetworkInterfaceType.Wwanpp => "无线广域网PP",
NetworkInterfaceType.Wwanpp2 => "无线广域网PP2",
_ => type.ToString()
};
}
/// <summary>
/// 获取系统运行时间
/// </summary>
/// <returns>系统运行时间</returns>
public static TimeSpan GetSystemUptime()
{
return TimeSpan.FromMilliseconds(Environment.TickCount64);
}
/// <summary>
/// 获取外网IP地址
/// </summary>
/// <param name="cancellationToken">取消令牌</param>
/// <returns>外网IP信息</returns>
public static async Task<ExternalIPInfo> GetExternalIPAsync(CancellationToken cancellationToken = default)
{
var externalInfo = new ExternalIPInfo();
using var client = new HttpClient();
client.Timeout = TimeSpan.FromSeconds(10);
// 获取IPv4地址
externalInfo.IPv4 = await GetIPv4AddressAsync(client, cancellationToken);
// 获取IPv6地址
externalInfo.IPv6 = await GetIPv6AddressAsync(client, cancellationToken);
return externalInfo;
}
#endregion
#region 私有方法
/// <summary>
/// 获取IPv4外网地址
/// </summary>
private static async Task<string> GetIPv4AddressAsync(HttpClient client, CancellationToken cancellationToken)
{
var ipv4Services = new[]
{
"https://api.ipify.org",
"https://icanhazip.com",
"https://ipv4.icanhazip.com",
"https://checkip.amazonaws.com"
};
foreach (var service in ipv4Services)
{
try
{
var response = await client.GetStringAsync(service, cancellationToken);
var ip = response?.Trim();
if (!string.IsNullOrEmpty(ip) && IPAddress.TryParse(ip, out _))
{
return ip;
}
}
catch (Exception ex)
{
Log.Debug($"获取IPv4地址失败 ({service}): {ex.Message}");
}
}
return "无法获取";
}
/// <summary>
/// 获取IPv6外网地址
/// </summary>
private static async Task<string> GetIPv6AddressAsync(HttpClient client, CancellationToken cancellationToken)
{
var ipv6Services = new[]
{
"https://api6.ipify.org",
"https://ipv6.icanhazip.com"
};
foreach (var service in ipv6Services)
{
try
{
var response = await client.GetStringAsync(service, cancellationToken);
var ip = response?.Trim();
if (!string.IsNullOrEmpty(ip) && IPAddress.TryParse(ip, out _))
{
return ip;
}
}
catch (Exception ex)
{
Log.Debug($"获取IPv6地址失败 ({service}): {ex.Message}");
}
}
return "不支持或无法获取";
}
#endregion
}
/// <summary>
/// 外网IP信息
/// </summary>
public class ExternalIPInfo
{
public string IPv4 { get; set; } = string.Empty;
public string IPv6 { get; set; } = string.Empty;
public string ISP { get; set; } = string.Empty;
public string Location { get; set; } = string.Empty;
}
/// <summary>
/// 网速信息
/// </summary>
public class NetworkSpeed
{
public double DownloadSpeed { get; set; }
public double UploadSpeed { get; set; }
public double TotalSpeed => DownloadSpeed + UploadSpeed;
public string DownloadSpeedText => NetworkHelper.FormatSpeed(DownloadSpeed);
public string UploadSpeedText => NetworkHelper.FormatSpeed(UploadSpeed);
public string TotalSpeedText => NetworkHelper.FormatSpeed(TotalSpeed);
}
}
@@ -1,193 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Net.NetworkInformation;
using System.Runtime.InteropServices;
using NetVizor.Common.Models;
namespace NetVizor.Common.Utils
{
/// <summary>
/// Provides utility methods to retrieve network interface information
/// using the Windows IP Helper API (iphlpapi.dll).
/// This class does not require administrator privileges.
/// </summary>
public static class NetworkInfoUtil
{
#region P/Invoke Definitions
private const int ERROR_SUCCESS = 0;
private const int MAX_INTERFACE_NAME_LEN = 256;
private const int MAXLEN_PHYSADDR = 8;
private const int MAXLEN_IFDESCR = 256;
[DllImport("iphlpapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern uint GetIfTable2(out IntPtr pIfTable);
[DllImport("iphlpapi.dll", SetLastError = true)]
private static extern void FreeMibTable(IntPtr pMibTable);
private enum TunnelType
{
TUNNEL_TYPE_NONE = 0,
TUNNEL_TYPE_OTHER = 1,
TUNNEL_TYPE_DIRECT = 2,
TUNNEL_TYPE_6TO4 = 11,
TUNNEL_TYPE_ISATAP = 13,
TUNNEL_TYPE_TEREDO = 14,
TUNNEL_TYPE_IPHTTPS = 15
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct MIB_IF_ROW2
{
public long InterfaceLuid;
public uint InterfaceIndex;
public Guid InterfaceGuid;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_INTERFACE_NAME_LEN + 1)]
public string Alias;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAXLEN_IFDESCR + 1)]
public string Description;
public uint PhysicalAddressLength;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXLEN_PHYSADDR)]
public byte[] PhysicalAddress;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXLEN_PHYSADDR)]
public byte[] PermanentPhysicalAddress;
public uint Mtu;
public NetworkInterfaceType Type;
public TunnelType TunnelType;
public uint MediaConnectState;
public uint MediaDuplexState;
public uint InterfaceAndOperStatusFlags;
public OperationalStatus OperStatus;
public uint AdminStatus;
public uint NetLuidIndex;
public uint NdisMedium;
public uint NdisPhysicalMedium;
public uint HardareInterface;
// --- Start of Corrected Fields ---
public ulong ReceiveLinkSpeed;
public ulong TransmitLinkSpeed;
// --- End of Corrected Fields ---
public ulong OutOctets;
public ulong InOctets;
public ulong OutUcastPkts;
public ulong InUcastPkts;
public ulong OutNUcastPkts;
public ulong InNUcastPkts;
public ulong OutDiscards;
public ulong InDiscards;
public ulong OutErrors;
public ulong InErrors;
public ulong OutUcastOctets;
public ulong InUcastOctets;
public ulong OutMulticastOctets;
public ulong InMulticastOctets;
public ulong OutBroadcastOctets;
public ulong InBroadcastOctets;
public uint OutQLen;
}
[StructLayout(LayoutKind.Sequential)]
private struct MIB_IF_TABLE2
{
public uint NumEntries;
// The Table field is a placeholder here. We'll calculate its position manually.
}
#endregion
/// <summary>
/// Gets a list of all network interfaces on the system.
/// </summary>
/// <returns>A list of NetworkInterfaceInfo objects.</returns>
/// <exception cref="Win32Exception">Thrown if the underlying Windows API call fails.</exception>
public static List<NetworkInterfaceInfo> GetAllInterfaces()
{
IntPtr pIfTable = IntPtr.Zero;
try
{
uint result = GetIfTable2(out pIfTable);
if (result != ERROR_SUCCESS)
{
throw new Win32Exception((int)result);
}
var ifTable = (MIB_IF_TABLE2)Marshal.PtrToStructure(pIfTable, typeof(MIB_IF_TABLE2));
var interfaces = new List<NetworkInterfaceInfo>((int)ifTable.NumEntries);
IntPtr currentPtr = new IntPtr(pIfTable.ToInt64() + Marshal.SizeOf(typeof(uint)));
for (int i = 0; i < ifTable.NumEntries; i++)
{
var row = (MIB_IF_ROW2)Marshal.PtrToStructure(currentPtr, typeof(MIB_IF_ROW2));
interfaces.Add(MapRowToInterfaceInfo(row));
currentPtr = new IntPtr(currentPtr.ToInt64() + Marshal.SizeOf(typeof(MIB_IF_ROW2)));
}
return interfaces;
}
finally
{
if (pIfTable != IntPtr.Zero)
{
FreeMibTable(pIfTable);
}
}
}
/// <summary>
/// Gets detailed information for a specific network interface by its index.
/// </summary>
/// <param name="interfaceIndex">The index of the interface to retrieve.</param>
/// <returns>A NetworkInterfaceInfo object, or null if not found.</returns>
public static NetworkInterfaceInfo? GetInterfaceByIndex(uint interfaceIndex)
{
var allInterfaces = GetAllInterfaces();
foreach (var iface in allInterfaces)
{
if (iface.Index == interfaceIndex)
{
return iface;
}
}
return null;
}
private static NetworkInterfaceInfo MapRowToInterfaceInfo(MIB_IF_ROW2 row)
{
// Guard against invalid address length reported by the API
int macAddrLen = (int)Math.Min(row.PhysicalAddressLength, (uint)MAXLEN_PHYSADDR);
var macBytes = new byte[macAddrLen];
if (macAddrLen > 0)
{
Array.Copy(row.PhysicalAddress, macBytes, macAddrLen);
}
return new NetworkInterfaceInfo
{
Index = row.InterfaceIndex,
InterfaceId = row.InterfaceGuid.ToString(),
Alias = row.Alias,
Description = row.Description,
Type = row.Type,
Status = row.OperStatus,
Speed = row.ReceiveLinkSpeed, // Correctly use the speed field from the struct
MacAddress = macAddrLen > 0 ? BitConverter.ToString(macBytes).Replace('-', ':') : string.Empty,
BytesSent = (long)row.OutOctets,
BytesReceived = (long)row.InOctets
};
}
}
}
@@ -0,0 +1,311 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Net.NetworkInformation;
using Common.Logger;
namespace Common.Utils
{
/// <summary>
/// 网络监控帮助类 - 使用 .NET 内置的 NetworkInterface 类
/// </summary>
public class NetworkMonitorHelper1
{
#region 公共类和方法
/// <summary>
/// 网络接口信息
/// </summary>
public class NetworkInterface
{
public string Name { get; set; }
public string Description { get; set; }
public string Id { get; set; }
public uint Index { get; set; }
public long BytesReceived { get; set; }
public long BytesSent { get; set; }
public bool IsConnected { get; set; }
public NetworkInterfaceType Type { get; set; }
public string TypeDescription { get; set; }
public override string ToString()
{
return Name;
}
}
/// <summary>
/// 网速信息
/// </summary>
public class NetworkSpeed
{
public double DownloadSpeed { get; set; } // bytes per second
public double UploadSpeed { get; set; } // bytes per second
public double TotalSpeed => DownloadSpeed + UploadSpeed;
// 格式化显示
public string DownloadSpeedText => FormatSpeed(DownloadSpeed);
public string UploadSpeedText => FormatSpeed(UploadSpeed);
public string TotalSpeedText => FormatSpeed(TotalSpeed);
private string FormatSpeed(double bytesPerSecond)
{
// 防止显示负数或异常大的数值
if (bytesPerSecond < 0 || double.IsNaN(bytesPerSecond) || double.IsInfinity(bytesPerSecond))
{
return "0.00 B/s";
}
string[] sizes = { "B/s", "KB/s", "MB/s", "GB/s" };
int order = 0;
while (bytesPerSecond >= 1024 && order < sizes.Length - 1)
{
order++;
bytesPerSecond = bytesPerSecond / 1024;
}
return $"{bytesPerSecond:0.00} {sizes[order]}";
}
}
// 缓存上次的统计数据
private static Dictionary<string, (long bytesReceived, long bytesSent, DateTime updateTime)> previousStats =
new Dictionary<string, (long, long, DateTime)>();
private static bool isFirstRun = true;
/// <summary>
/// 获取接口类型描述
/// </summary>
private static string GetInterfaceTypeDescription(NetworkInterfaceType type)
{
switch (type)
{
case NetworkInterfaceType.Ethernet:
return "以太网";
case NetworkInterfaceType.Wireless80211:
return "Wi-Fi";
case NetworkInterfaceType.Loopback:
return "环回接口";
case NetworkInterfaceType.Ppp:
return "PPP";
case NetworkInterfaceType.Tunnel:
return "隧道";
default:
return type.ToString();
}
}
/// <summary>
/// 获取所有网络接口
/// </summary>
public static List<NetworkInterface> GetNetworkInterfaces()
{
var interfaces = new List<NetworkInterface>();
try
{
var networkInterfaces = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces();
foreach (var ni in networkInterfaces)
{
// 跳过环回接口
if (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback)
{
Log.Info($"跳过环回接口: {ni.Name}");
continue;
}
// 获取IPv4统计信息
IPv4InterfaceStatistics stats = null;
try
{
stats = ni.GetIPv4Statistics();
}
catch (Exception ex)
{
Log.Error4Ctx($"无法获取接口 {ni.Name} 的统计信息: {ex.Message}");
continue;
}
var networkInterface = new NetworkInterface
{
Name = ni.Name,
Description = ni.Description,
Id = ni.Id,
Index = 0, // NetworkInterface 类不提供 Index,使用 Id 作为唯一标识
BytesReceived = stats.BytesReceived,
BytesSent = stats.BytesSent,
IsConnected = ni.OperationalStatus == OperationalStatus.Up,
Type = ni.NetworkInterfaceType,
TypeDescription = GetInterfaceTypeDescription(ni.NetworkInterfaceType)
};
interfaces.Add(networkInterface);
}
}
catch (Exception ex)
{
Log.Error4Ctx($"获取网络接口时发生错误: {ex.Message}");
Log.Error4Ctx($"错误堆栈: {ex.StackTrace}");
}
return interfaces;
}
/// <summary>
/// 计算指定网络接口的网速
/// </summary>
public static NetworkSpeed CalculateSpeed(uint interfaceIndex)
{
// 由于使用了 NetworkInterface 类,这里改为使用接口名称查找
var interfaces = GetNetworkInterfaces();
return CalculateSpeedByName(interfaces, interfaceIndex.ToString());
}
/// <summary>
/// 根据接口名称计算网速
/// </summary>
public static NetworkSpeed CalculateSpeedByName(string interfaceName)
{
var interfaces = GetNetworkInterfaces();
return CalculateSpeedByName(interfaces, interfaceName);
}
private static NetworkSpeed CalculateSpeedByName(List<NetworkInterface> currentInterfaces, string interfaceName)
{
Log.Info($"计算接口 {interfaceName} 的网速...");
var currentInterface =
currentInterfaces.FirstOrDefault(i => i.Name == interfaceName || i.Id == interfaceName);
if (currentInterface == null)
{
Log.Warning($"未找到接口 {interfaceName}");
return new NetworkSpeed();
}
var now = DateTime.Now;
var speed = new NetworkSpeed();
string key = currentInterface.Id;
// 如果是第一次运行或没有该接口的历史数据,只保存数据
if (isFirstRun || !previousStats.ContainsKey(key))
{
previousStats[key] = (currentInterface.BytesReceived, currentInterface.BytesSent, now);
Log.Info($"接口 {interfaceName} 第一次记录数据");
if (isFirstRun) isFirstRun = false;
return speed;
}
var (prevBytesReceived, prevBytesSent, lastUpdateTime) = previousStats[key];
var timeDiff = (now - lastUpdateTime).TotalSeconds;
Log.Debug($"时间差: {timeDiff}秒");
if (timeDiff > 0.5) // 至少0.5秒的间隔
{
// 计算字节差
long downloadBytes = currentInterface.BytesReceived - prevBytesReceived;
long uploadBytes = currentInterface.BytesSent - prevBytesSent;
Log.Info($"下载字节差: {downloadBytes}, 上传字节差: {uploadBytes}");
// 防止计数器重置或异常值
if (downloadBytes >= 0 && downloadBytes < 1000000000) // 小于1GB/s
{
speed.DownloadSpeed = downloadBytes / timeDiff;
}
if (uploadBytes >= 0 && uploadBytes < 1000000000) // 小于1GB/s
{
speed.UploadSpeed = uploadBytes / timeDiff;
}
Log.Info($"接口 {interfaceName} - 下载: {speed.DownloadSpeedText}, 上传: {speed.UploadSpeedText}");
// 更新缓存
previousStats[key] = (currentInterface.BytesReceived, currentInterface.BytesSent, now);
}
return speed;
}
/// <summary>
/// 计算所有网络接口的总网速
/// </summary>
public static NetworkSpeed CalculateTotalSpeed()
{
var currentInterfaces = GetNetworkInterfaces();
var now = DateTime.Now;
var totalSpeed = new NetworkSpeed();
// 如果是第一次运行,只保存数据
if (isFirstRun)
{
foreach (var currentInterface in currentInterfaces)
{
previousStats[currentInterface.Id] =
(currentInterface.BytesReceived, currentInterface.BytesSent, now);
}
isFirstRun = false;
Log.Info("第一次运行,初始化数据");
return totalSpeed;
}
foreach (var currentInterface in currentInterfaces)
{
string key = currentInterface.Id;
if (previousStats.ContainsKey(key))
{
var (prevBytesReceived, prevBytesSent, lastUpdateTime) = previousStats[key];
var timeDiff = (now - lastUpdateTime).TotalSeconds;
if (timeDiff > 0.5) // 至少0.5秒的间隔
{
long downloadBytes = currentInterface.BytesReceived - prevBytesReceived;
long uploadBytes = currentInterface.BytesSent - prevBytesSent;
// 防止计数器重置或异常值
if (downloadBytes >= 0 && downloadBytes < 1000000000) // 小于1GB/s
{
totalSpeed.DownloadSpeed += downloadBytes / timeDiff;
}
if (uploadBytes >= 0 && uploadBytes < 1000000000) // 小于1GB/s
{
totalSpeed.UploadSpeed += uploadBytes / timeDiff;
}
// 更新缓存
previousStats[key] = (currentInterface.BytesReceived, currentInterface.BytesSent, now);
}
}
else
{
// 新接口,添加到缓存
previousStats[key] = (currentInterface.BytesReceived, currentInterface.BytesSent, now);
}
}
Log.Info($"总网速 - 下载: {totalSpeed.DownloadSpeedText}, 上传: {totalSpeed.UploadSpeedText}");
return totalSpeed;
}
/// <summary>
/// 重置统计数据
/// </summary>
public static void ResetStatistics()
{
Log.Info("重置网络统计数据");
previousStats.Clear();
isFirstRun = true;
}
#endregion
}
}
@@ -1,72 +0,0 @@
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using NetVizor.Common.Models;
namespace NetVizor.Common.Utils
{
/// <summary>
/// Monitors the real-time network speed (upload/download) for a specific network interface.
/// </summary>
public class NetworkSpeedMonitor
{
private readonly uint _interfaceIndex;
private long _lastBytesSent;
private long _lastBytesReceived;
private DateTime _lastUpdateTime;
/// <summary>
/// Gets the real-time download speed in bytes per second.
/// </summary>
public double DownloadSpeedBps { get; private set; }
/// <summary>
/// Gets the real-time upload speed in bytes per second.
/// </summary>
public double UploadSpeedBps { get; private set; }
/// <summary>
/// Initializes a new instance of the NetworkSpeedMonitor for a given interface.
/// </summary>
/// <param name="interfaceInfo">The network interface to monitor.</param>
public NetworkSpeedMonitor(NetworkInterfaceInfo interfaceInfo)
{
_interfaceIndex = interfaceInfo.Index;
_lastBytesSent = interfaceInfo.BytesSent;
_lastBytesReceived = interfaceInfo.BytesReceived;
_lastUpdateTime = DateTime.UtcNow;
}
/// <summary>
/// Updates the speed calculation. This method should be called periodically.
/// </summary>
public void Update()
{
var currentInterfaceInfo = NetworkInfoUtil.GetInterfaceByIndex(_interfaceIndex);
if (currentInterfaceInfo == null)
{
DownloadSpeedBps = 0;
UploadSpeedBps = 0;
return;
}
var currentTime = DateTime.UtcNow;
var timeSpan = (currentTime - _lastUpdateTime).TotalSeconds;
if (timeSpan <= 0)
{
return; // Avoid division by zero if called too quickly
}
long bytesSent = currentInterfaceInfo.BytesSent;
long bytesReceived = currentInterfaceInfo.BytesReceived;
UploadSpeedBps = (bytesSent - _lastBytesSent) / timeSpan;
DownloadSpeedBps = (bytesReceived - _lastBytesReceived) / timeSpan;
_lastBytesSent = bytesSent;
_lastBytesReceived = bytesReceived;
_lastUpdateTime = currentTime;
}
}
}
@@ -8,6 +8,7 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FirewallManager" Version="1.0.2"/>
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.21" />
<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.4.25258.110" />
</ItemGroup>
@@ -0,0 +1,32 @@
using NetFwTypeLib;
namespace NetVizor.Infrastructure.Models
{
// 用于定义防火墙规则的方向
public enum FirewallDirection
{
In,
Out
}
// 用于定义防火墙规则的操作
public enum FirewallAction
{
Block,
Allow
}
public class FirewallRule
{
public string Name { get; set; } = "";
public string? Description { get; set; }
public string? GroupName { get; set; }
public string ApplicationName { get; set; } = ""; // "*" 表示所有程序
public string Protocol { get; set; } = "TCP"; // TCP, UDP, ANY
public string LocalPorts { get; set; } = "*"; // "80,443" 或 "*"
public string RemotePorts { get; set; } = "*";
public FirewallDirection Direction { get; set; } = FirewallDirection.In;
public FirewallAction Action { get; set; } = FirewallAction.Allow;
public bool Enabled { get; set; } = true;
}
}
@@ -313,4 +313,5 @@ public static class SysInfoUtils
return $"{len:0.##} {sizes[order]}";
}
}
}
// Infrastructure.utils FormatBytes
@@ -32,6 +32,7 @@
<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>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ANetworkInterfaceType_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F92cb821cac5045cbbf918dc41b2ea2ca26920_003Fa4_003F57cbd2f9_003FNetworkInterfaceType_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>
+18 -6
View File
@@ -1,10 +1,22 @@
<Application x:Class="Shell.App"
<Application x:Class="NetVizor.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Shell"
>
<!-- StartupUri="MainWindow.xaml" -->
xmlns:local="clr-namespace:NetVizor"
xmlns:converters="clr-namespace:NetVizor.Views.Converters"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<converters:NullToCollapsedConverter x:Key="NullToCollapsedConverter" />
<converters:NullToVisibleConverter x:Key="NullToVisibleConverter" />
<!-- 全局样式 -->
<Style TargetType="TextBlock">
<Setter Property="FontFamily" Value="Microsoft YaHei" />
</Style>
<Style TargetType="ComboBox">
<Setter Property="FontFamily" Value="Microsoft YaHei" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
</Application>
+5 -3
View File
@@ -8,6 +8,7 @@ using System.Text.Json;
using System.Web;
using System.Windows;
using System.Windows.Threading;
using Application;
using Application.Utils;
using Common;
using Common.Logger;
@@ -18,9 +19,10 @@ using Common.Utils;
using Infrastructure.Models;
using Microsoft.Extensions.Logging;
using Serilog.Events;
using Shell;
using Utils.ETW.Etw;
namespace Shell;
namespace NetVizor;
/// <summary>
/// Interaction logic for App.xaml
@@ -36,8 +38,8 @@ public partial class App : System.Windows.Application
Log.Initialize(configModelLogging);
base.OnStartup(e);
// ✅ 启动你的服务(如 WebSocket、HTTP、端口监听等)
StartMyServer();
// 启动服务(如 WebSocket、HTTP、端口监听等)
// StartMyServer();
}
/// <summary>
+12 -5
View File
@@ -3,11 +3,18 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Shell"
xmlns:views="clr-namespace:Shell.Views"
xmlns:local="clr-namespace:NetVizor"
xmlns:views1="clr-namespace:Shell.Views"
mc:Ignorable="d"
Title="MainWindow" Height="700" Width="1300">
Title="NetVizor Dashboard" Height="700" Width="1300">
<Grid>
<views:WebPanel/>
<TabControl>
<TabItem Header="Network Monitor">
<views1:NetworkMonitorView />
</TabItem>
<TabItem Header="Web Panel">
<views1:WebPanel />
</TabItem>
</TabControl>
</Grid>
</Window>
</Window>
@@ -10,5 +10,6 @@ public partial class MainWindow : Window
public MainWindow()
{
InitializeComponent();
Console.WriteLine("1211111111111111111111111111。");
}
}
}
@@ -0,0 +1,171 @@
<UserControl x:Class="Shell.Views.NetworkMonitorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:NetVizor.Views"
xmlns:converters="clr-namespace:NetVizor.Views.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Background="#F0F2F5">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- 网络接口选择 -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="选择网络接口:" VerticalAlignment="Center" />
<ComboBox Grid.Column="1"
Name="cmbInterfaces"
Margin="5,0"
VerticalAlignment="Center"
SelectionChanged="cmbInterfaces_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0,0,10,0">
<TextBlock.Text>
<Binding Path="Name" />
</TextBlock.Text>
</TextBlock>
<TextBlock Grid.Column="1" Foreground="Gray">
<TextBlock.Text>
<Binding Path="Description" />
</TextBlock.Text>
</TextBlock>
<TextBlock Grid.Column="2" Margin="10,0,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding IsConnected}" Value="True">
<Setter Property="Text" Value="[已连接]" />
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding IsConnected}" Value="False">
<Setter Property="Text" Value="[未连接]" />
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Grid.Column="2"
Name="btnRefresh"
Content="刷新"
Padding="10,5"
Click="btnRefresh_Click" />
</Grid>
<!-- 网速显示区域 -->
<Border Grid.Row="2"
BorderBrush="#CCCCCC"
BorderThickness="1"
CornerRadius="5"
Background="#F9F9F9">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="20" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Text="实时网速监控"
FontSize="18"
FontWeight="Bold"
HorizontalAlignment="Center" />
<!-- 下载速度 -->
<Grid Grid.Row="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="▼" Foreground="Green" FontWeight="Bold" Margin="0,0,5,0" />
<TextBlock Text="下载速度:" FontSize="14" VerticalAlignment="Center" />
</StackPanel>
<TextBlock Grid.Column="1"
Name="txtDownloadSpeed"
Text="0.00 B/s"
FontSize="16"
FontWeight="Bold"
Foreground="Green"
VerticalAlignment="Center" />
</Grid>
<!-- 上传速度 -->
<Grid Grid.Row="3" Margin="0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="▲" Foreground="Blue" FontWeight="Bold" Margin="0,0,5,0" />
<TextBlock Text="上传速度:" FontSize="14" VerticalAlignment="Center" />
</StackPanel>
<TextBlock Grid.Column="1"
Name="txtUploadSpeed"
Text="0.00 B/s"
FontSize="16"
FontWeight="Bold"
Foreground="Blue"
VerticalAlignment="Center" />
</Grid>
<!-- 总速度 -->
<Grid Grid.Row="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<TextBlock Text="Σ" Foreground="DarkOrange" FontWeight="Bold" FontSize="16" Margin="0,0,5,0" />
<TextBlock Text="总速度:" FontSize="14" VerticalAlignment="Center" />
</StackPanel>
<TextBlock Grid.Column="1"
Name="txtTotalSpeed"
Text="0.00 B/s"
FontSize="16"
FontWeight="Bold"
Foreground="DarkOrange"
VerticalAlignment="Center" />
</Grid>
<!-- 状态信息 -->
<TextBlock Grid.Row="6"
Name="txtStatus"
Text="请选择一个网络接口"
FontSize="12"
Foreground="Gray"
HorizontalAlignment="Center" />
</Grid>
</Border>
</Grid>
</UserControl>
@@ -0,0 +1,212 @@
using System.Windows.Controls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Threading;
using Common.Logger;
using Common.Utils;
namespace Shell.Views
{
/// <summary>
/// Interaction logic for NetworkMonitorView.xaml
/// </summary>
public partial class NetworkMonitorView : UserControl
{
private DispatcherTimer updateTimer;
private List<NetworkMonitorHelper1.NetworkInterface> interfaces;
private const string SELECT_ALL_TEXT = "选择全部";
public NetworkMonitorView()
{
InitializeComponent();
Log.Info("NetworkMonitorControl 初始化");
// 初始化定时器
updateTimer = new DispatcherTimer();
updateTimer.Interval = TimeSpan.FromSeconds(1); // 每秒更新一次
updateTimer.Tick += UpdateTimer_Tick;
// 控件加载完成后初始化
Loaded += NetworkMonitorControl_Loaded;
Unloaded += NetworkMonitorControl_Unloaded;
// NewMethod();
}
private static async Task NewMethod()
{
// 获取详细信息
var interfaces = EnhancedNetworkMonitor.GetDetailedNetworkInterfaces();
var json = JsonHelper.ToJson(interfaces);
Console.WriteLine(json);
// 获取完整报告
var report = await EnhancedNetworkMonitor.GetNetworkStatusReportAsync();
Console.WriteLine(report);
// 获取外网IP
var externalIP = await EnhancedNetworkMonitor.GetExternalIPAsync();
Console.WriteLine(externalIP);
}
private void NetworkMonitorControl_Loaded(object sender, RoutedEventArgs e)
{
Log.Info("NetworkMonitorControl 加载完成");
LoadNetworkInterfaces();
updateTimer.Start();
}
private void NetworkMonitorControl_Unloaded(object sender, RoutedEventArgs e)
{
Log.Info("NetworkMonitorControl 卸载");
updateTimer.Stop();
}
private void LoadNetworkInterfaces()
{
try
{
// 获取所有网络接口
interfaces = NetworkMonitorHelper1.GetNetworkInterfaces();
// 创建下拉框项目列表
var comboItems = new List<object>();
// 添加"选择全部"选项
comboItems.Add(new
{
Name = SELECT_ALL_TEXT,
Description = "显示所有网络接口的总网速",
TypeDescription = "",
IsConnected = true
});
// 添加所有非环回接口
foreach (var iface in interfaces)
{
// 添加所有接口到下拉框(环回接口已经在工具类中过滤)
comboItems.Add(iface);
}
// 更新下拉框
cmbInterfaces.ItemsSource = comboItems;
// 默认选择第一项(选择全部)
if (comboItems.Count > 0)
{
cmbInterfaces.SelectedIndex = 0;
}
else
{
txtStatus.Text = "未找到可用的网络接口";
Log.Warning("未找到任何网络接口");
}
}
catch (Exception ex)
{
Log.Error4Ctx($"加载网络接口时发生错误: {ex.Message}");
txtStatus.Text = $"加载失败: {ex.Message}";
}
}
private void UpdateTimer_Tick(object sender, EventArgs e)
{
if (cmbInterfaces.SelectedItem == null)
{
return;
}
try
{
dynamic selectedItem = cmbInterfaces.SelectedItem;
NetworkMonitorHelper1.NetworkSpeed speed;
if (selectedItem.Name == SELECT_ALL_TEXT)
{
// 计算所有接口的总网速
speed = NetworkMonitorHelper1.CalculateTotalSpeed();
txtStatus.Text = "显示所有网络接口的总网速";
}
else
{
// 计算指定接口的网速
var networkInterface = selectedItem as NetworkMonitorHelper1.NetworkInterface;
if (networkInterface != null)
{
speed = NetworkMonitorHelper1.CalculateSpeedByName(networkInterface.Name);
// 显示接口状态
string statusText = $"正在监控: {networkInterface.Name} ({networkInterface.TypeDescription})";
if (!networkInterface.IsConnected)
{
statusText += " - 未连接";
}
txtStatus.Text = statusText;
}
else
{
return;
}
}
// 更新界面显示
Dispatcher.Invoke(() =>
{
txtDownloadSpeed.Text = speed.DownloadSpeedText;
txtUploadSpeed.Text = speed.UploadSpeedText;
txtTotalSpeed.Text = speed.TotalSpeedText;
});
}
catch (Exception ex)
{
Log.Error4Ctx($"更新网速时发生错误: {ex.Message}");
txtStatus.Text = $"更新失败: {ex.Message}";
}
}
private void cmbInterfaces_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Log.Info("用户切换了网络接口选择");
// 重置网速显示
txtDownloadSpeed.Text = "0.00 B/s";
txtUploadSpeed.Text = "0.00 B/s";
txtTotalSpeed.Text = "0.00 B/s";
// 重置统计数据,以便立即开始新的统计
NetworkMonitorHelper1.ResetStatistics();
if (cmbInterfaces.SelectedItem != null)
{
dynamic selectedItem = cmbInterfaces.SelectedItem;
Log.Info($"选择了: {selectedItem.Name}");
}
}
private void btnRefresh_Click(object sender, RoutedEventArgs e)
{
Log.Info("用户点击了刷新按钮");
// 停止定时器
updateTimer.Stop();
// 重置统计数据
NetworkMonitorHelper1.ResetStatistics();
// 重新加载接口
LoadNetworkInterfaces();
// 重启定时器
updateTimer.Start();
txtStatus.Text = "接口列表已刷新";
}
}
}
@@ -30,21 +30,20 @@ public partial class WebPanel : UserControl
// ETW 信息获取
// 检查管理员权限
NewMethod();
// NewMethod();
}
private static async Task NewMethod()
{
if (!SysHelper.IsAdministrator())
{
Console.WriteLine("此程序需要管理员权限才能运行ETW监控!");
Console.WriteLine("请以管理员身份重新运行程序。");
Console.ReadKey();
Log.Info("此程序需要管理员权限才能运行ETW监控!");
Log.Info("请以管理员身份重新运行程序。");
return;
}
var example = new NetworkMonitorUsageExample();
example.RunExample();
// var example = new NetworkMonitorUsageExample();
// example.RunExample();
// 创建监听实例
// var etwNetworkManger = new EtwNetworkManger();
@@ -60,8 +59,6 @@ public partial class WebPanel : UserControl
// 获取网络状态
webSocketManager.RegisterHandler("etwNetworkManger", async (cmd, socket) =>
{
Console.WriteLine("开始测试");
// 创建监听实例
// var etwNetworkManger = new EtwNetworkManger();
@@ -166,8 +163,8 @@ public partial class WebPanel : UserControl
public class JsMessage
{
public string Channel { get; set; }
public JsData Payload { get; set; }
public string Channel { get; set; }
public JsData Payload { get; set; }
public override string ToString()
{
@@ -177,8 +174,8 @@ public JsData Payload { get; set; }
public class JsData
{
public string Title { get; set; }
public string Content { get; set; }
public string Title { get; set; }
public string Content { get; set; }
public override string ToString()
{
@@ -1,3 +1,4 @@
using Common.Logger;
using Microsoft.Diagnostics.Tracing;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
@@ -5,7 +6,6 @@ using Utils.ETW.Models;
namespace Utils.ETW.Core;
// ETW网络事件处理器
public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisposable
{
@@ -13,6 +13,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
/// 此代码需要管理员权限
/// </summary>
private readonly TraceEventSession _session = new(sessionName);
private readonly ETWTraceEventSource _source = new(sessionName, TraceEventSourceType.Session);
/// <summary>
@@ -36,11 +37,12 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
public delegate void NetworkErrorEventHandler(NetworkErrorEventData eventData);
// 事件处理器
/// <summary>
/// 通用网络事件处理,所有的网络事件都会进入该函数
/// </summary>
public event NetworkEventHandler? OnNetworkEvent;
public event TcpConnectionEventHandler? OnTcpConnectionEvent;
public event UdpPacketEventHandler? OnUdpPacketEvent;
public event DnsEventHandler? OnDnsEvent;
@@ -68,11 +70,11 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
// 开始处理事件(这是阻塞调用)
Task.Run(() => { _source.Process(); });
Console.WriteLine("ETW网络捕获已启动...");
Log.Info("ETW网络捕获已启动...");
}
catch (Exception ex)
{
Console.WriteLine($"启动ETW捕获失败: {ex.Message}");
Log.Info($"启动ETW捕获失败: {ex.Message}");
throw;
}
}
@@ -197,7 +199,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
OnTcpConnectionEvent?.Invoke(tcpEvent);
OnNetworkEvent?.Invoke(tcpEvent);
};
// TCP数据接收事件 ETW Event ID 11
parser.TcpIpRecv += data =>
{
@@ -270,12 +272,12 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
OnNetworkEvent?.Invoke(udpEvent);
};
// 建议添加进程事件监控以获取完整进程信息
parser.ProcessStart += data => {
parser.ProcessStart += data =>
{
// 缓存进程信息,包括完整路径、命令行等
};
// 通用事件处理器,用于其他网络事件
_source.Dynamic.All += ProcessDynamicEvent;
}
/// <summary>
@@ -296,13 +298,13 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
case "Microsoft-Windows-NetworkProfile":
ProcessNetworkInterfaceEvent(data);
break;
// 负责 TCP/IP 协议栈事件,如连接、发送、接收、断开、重传等
// 用于监控 TCP 会话生命周期,是连接追踪的核心
// 负责 TCP/IP 协议栈事件,如连接、发送、接收、断开、重传等
// 用于监控 TCP 会话生命周期,是连接追踪的核心
case "Microsoft-Windows-TCPIP":
// AFD(Ancillary Function Driver for WinSock)是 Winsock API 的核心内核模块
// 常用于检测哪一个进程创建了 socket,socket 和 TCP 会话的关联
// AFD(Ancillary Function Driver for WinSock)是 Winsock API 的核心内核模块
// 常用于检测哪一个进程创建了 socket,socket 和 TCP 会话的关联
case "Microsoft-Windows-Winsock-AFD":
// 也叫 Kernel-Network
// 也叫 Kernel-Network
case "MSNT_SystemTrace":
break;
default:
@@ -337,7 +339,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
}
catch (Exception ex)
{
Console.WriteLine($"处理DNS事件时出错: {ex.Message}");
Log.Info($"处理DNS事件时出错: {ex.Message}");
}
}
@@ -366,7 +368,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
}
catch (Exception ex)
{
Console.WriteLine($"处理HTTP事件时出错: {ex.Message}");
Log.Info($"处理HTTP事件时出错: {ex.Message}");
}
}
@@ -396,7 +398,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
}
catch (Exception ex)
{
Console.WriteLine($"处理网络接口事件时出错: {ex.Message}");
Log.Info($"处理网络接口事件时出错: {ex.Message}");
}
}
@@ -416,7 +418,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
ThreadId = data.ThreadID,
ProcessName = data.ProcessName
};
Console.WriteLine($"data.PayloadName :=> {data.ProviderName}");
Log.Info($"data.PayloadName :=> {data.ProviderName}");
// 提取通用网络信息
foreach (var payloadName in data.PayloadNames)
@@ -436,7 +438,7 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
}
catch (Exception ex)
{
Console.WriteLine($"处理通用网络事件时出错: {ex.Message}");
Log.Info($"处理通用网络事件时出错: {ex.Message}");
}
}
@@ -449,11 +451,11 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
_isCapturing = false;
_session.Stop();
_source.Dispose();
Console.WriteLine("ETW网络捕获已停止");
Log.Info("ETW网络捕获已停止");
}
catch (Exception ex)
{
Console.WriteLine($"停止ETW捕获时出错: {ex.Message}");
Log.Info($"停止ETW捕获时出错: {ex.Message}");
}
}
@@ -463,4 +465,4 @@ public class EtwNetworkCapture(string sessionName = "NetworkETWSession") : IDisp
_session.Dispose();
_source.Dispose();
}
}
}
@@ -1,4 +1,5 @@
using System.Collections.Concurrent;
using Common.Logger;
using Utils.ETW.EtwTracker;
using Utils.ETW.Models;
@@ -8,10 +9,7 @@ public class HttpTracker : INetTracker
{
public void SetupEtwHandlers(EtwNetworkCapture networkCapture)
{
networkCapture.OnHttpEvent += httpEvent =>
{
Console.WriteLine($"[HTTP] {httpEvent.HttpMethod} {httpEvent.Url}");
};
networkCapture.OnHttpEvent += httpEvent => { Log.Info($"[HTTP] {httpEvent.HttpMethod} {httpEvent.Url}"); };
}
}
@@ -21,7 +19,7 @@ public class NetworkProfileTracker : INetTracker
{
networkCapture.OnNetworkInterfaceEvent += interfaceEvent =>
{
Console.WriteLine($"[Interface] {interfaceEvent.InterfaceName}: {interfaceEvent.InterfaceState}");
Log.Info($"[Interface] {interfaceEvent.InterfaceName}: {interfaceEvent.InterfaceState}");
};
}
}
@@ -64,8 +62,8 @@ public class EtwNetworkManger
// TCP
// _tcpTracker.SetupEtwHandlers(networkCapture);
Console.WriteLine("进入了!!!!!!!!!!");
Log.Info("进入了!!!!!!!!!!");
// DNS
dnsTracker.SetupEtwHandlers(networkCapture);
@@ -1,4 +1,5 @@
using System.Net;
using Common.Logger;
using Utils.ETW.EtwTracker;
using Utils.ETW.Models;
@@ -13,8 +14,8 @@ public class UdpTracker : INetTracker
{
networkCapture.OnUdpPacketEvent += (udpEvent) =>
{
Console.WriteLine($"[UDP] {udpEvent.EventType}: {udpEvent.SourceIp}:{udpEvent.SourcePort} -> " +
$"{udpEvent.DestinationIp}:{udpEvent.DestinationPort} ({udpEvent.DataLength} bytes)");
Log.Info($"[UDP] {udpEvent.EventType}: {udpEvent.SourceIp}:{udpEvent.SourcePort} -> " +
$"{udpEvent.DestinationIp}:{udpEvent.DestinationPort} ({udpEvent.DataLength} bytes)");
switch (udpEvent.EventType)
{
@@ -100,9 +101,10 @@ public class UdpTracker : INetTracker
ProcessName = eventData.ProcessName
};
NetworkInfoManger.Instance.SetUdpCache( networkModel);
NetworkInfoManger.Instance.SetUdpCache(networkModel);
string str = $"UDP 会话开始: {networkModel.SourceIp}:{networkModel.SourcePort} -> {networkModel.DestinationIp}:{networkModel.DestinationPort}";
string str =
$"UDP 会话开始: {networkModel.SourceIp}:{networkModel.SourcePort} -> {networkModel.DestinationIp}:{networkModel.DestinationPort}";
NetworkInfoManger.Instance.RecordEvent(str);
}
else
@@ -111,19 +113,20 @@ public class UdpTracker : INetTracker
existingSession.BytesSent += eventData.UdpLength;
existingSession.LastSeenTime = now;
}
if (eventData.DataLength < 0)
{
throw new Exception("数据长度不可能为 0 !!");
}
// 统计端口流量
NetworkInfoManger.Instance.PortTrafficSent.TryAdd(eventData.DestinationPort, 0);
NetworkInfoManger.Instance.PortTrafficSent[eventData.DestinationPort] += (ulong)eventData.DataLength;
NetworkInfoManger.Instance.SourceTrafficSent.TryAdd(eventData.SourceIp, 0);
NetworkInfoManger.Instance.SourceTrafficSent[eventData.SourceIp] += (ulong)eventData.DataLength;
// UDP处理主要关注数据包本身,而不是连接状态
UpdateTrafficStats(eventData);
}
@@ -178,9 +181,10 @@ public class UdpTracker : INetTracker
ProcessName = eventData.ProcessName
};
NetworkInfoManger.Instance.SetUdpCache( networkModel);
NetworkInfoManger.Instance.SetUdpCache(networkModel);
string str = $"UDP 会话开始: {networkModel.SourceIp}:{networkModel.SourcePort} -> {networkModel.DestinationIp}:{networkModel.DestinationPort}";
string str =
$"UDP 会话开始: {networkModel.SourceIp}:{networkModel.SourcePort} -> {networkModel.DestinationIp}:{networkModel.DestinationPort}";
NetworkInfoManger.Instance.RecordEvent(str);
}
else
@@ -189,11 +193,12 @@ public class UdpTracker : INetTracker
existingSession.BytesReceived += eventData.UdpLength;
existingSession.LastSeenTime = now;
}
if (eventData.DataLength < 0)
{
throw new Exception("数据长度不可能为 0 !!");
}
// 统计端口流量
NetworkInfoManger.Instance.PortTrafficReceived.TryAdd(eventData.DestinationPort, 0);
NetworkInfoManger.Instance.PortTrafficReceived[eventData.DestinationPort] += (ulong)eventData.DataLength;
@@ -214,7 +219,7 @@ public class UdpTracker : INetTracker
sourceTraffic.TryAdd(udpEvent.SourceIp, 0);
sourceTraffic[udpEvent.SourceIp] += udpEvent.DataLength;
}
/// <summary>
/// 因为 UDP 无断开标志,所以需要一个定期清理机制
/// </summary>
@@ -229,7 +234,8 @@ public class UdpTracker : INetTracker
{
NetworkInfoManger.Instance.RemoveUdpSession(session);
string str = $"UDP 会话结束: {session.SourceIp}:{session.SourcePort} -> {session.DestinationIp}:{session.DestinationPort}";
string str =
$"UDP 会话结束: {session.SourceIp}:{session.SourcePort} -> {session.DestinationIp}:{session.DestinationPort}";
NetworkInfoManger.Instance.RecordEvent(str);
}
}
@@ -246,7 +252,7 @@ public class UdpTracker : INetTracker
private void ProcessDhcpPacket(UdpPacketEventData udpEvent)
{
Console.WriteLine($"[DHCP] DHCP通信: {udpEvent.SourceIp} <-> {udpEvent.DestinationIp}");
Log.Info($"[DHCP] DHCP通信: {udpEvent.SourceIp} <-> {udpEvent.DestinationIp}");
}
private void ProcessGenericUdpPacket(UdpPacketEventData udpEvent)
@@ -254,24 +260,24 @@ public class UdpTracker : INetTracker
// 对于未知UDP流量,主要进行安全检查
if (udpEvent.DataLength > 1024 * 64) // 64KB
{
Console.WriteLine($"[UDP警告] 大型UDP数据包: {udpEvent.ProcessName} " +
$"发送 {udpEvent.DataLength} 字节到 {udpEvent.DestinationIp}:{udpEvent.DestinationPort}");
Log.Info($"[UDP警告] 大型UDP数据包: {udpEvent.ProcessName} " +
$"发送 {udpEvent.DataLength} 字节到 {udpEvent.DestinationIp}:{udpEvent.DestinationPort}");
}
}
public void PrintTrafficSummary()
{
Console.WriteLine("\n=== UDP流量统计 ===");
Console.WriteLine("端口流量TOP 10:");
Log.Info("\n=== UDP流量统计 ===");
Log.Info("端口流量TOP 10:");
foreach (var item in portTraffic.OrderByDescending(x => x.Value).Take(10))
{
Console.WriteLine($" 端口 {item.Key}: {item.Value / 1024}KB");
Log.Info($" 端口 {item.Key}: {item.Value / 1024}KB");
}
Console.WriteLine("\n源IP流量TOP 10:");
Log.Info("\n源IP流量TOP 10:");
foreach (var item in sourceTraffic.OrderByDescending(x => x.Value).Take(10))
{
Console.WriteLine($" {item.Key}: {item.Value / 1024}KB");
Log.Info($" {item.Key}: {item.Value / 1024}KB");
}
}
}
}
@@ -1,6 +1,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Net;
using Common.Logger;
using Infrastructure.utils;
using Utils.ETW.Core;
using Utils.ETW.Models;
@@ -63,7 +64,7 @@ public class EnhancedEtwNetworkManager : IDisposable
Task.Run(() => ProcessDnsLookupsAsync(_cancellationTokenSource.Token));
Task.Run(() => CleanupExpiredDataAsync(_cancellationTokenSource.Token));
Console.WriteLine("增强型网络监控已启动");
Log.Info("增强型网络监控已启动");
}
/// <summary>
@@ -77,7 +78,7 @@ public class EnhancedEtwNetworkManager : IDisposable
_cancellationTokenSource.Cancel();
_networkCapture.StopCapture();
Console.WriteLine("增强型网络监控已停止");
Log.Info("增强型网络监控已停止");
}
#region 事件处理方法
@@ -146,7 +147,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"处理TCP事件时出错: {ex.Message}");
Log.Info($"处理TCP事件时出错: {ex.Message}");
}
}
@@ -195,7 +196,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"处理UDP事件时出错: {ex.Message}");
Log.Info($"处理UDP事件时出错: {ex.Message}");
}
}
@@ -214,7 +215,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"处理DNS事件时出错: {ex.Message}");
Log.Info($"处理DNS事件时出错: {ex.Message}");
}
}
@@ -223,11 +224,11 @@ public class EnhancedEtwNetworkManager : IDisposable
try
{
// 可以从HTTP事件中提取更多应用层信息
Console.WriteLine($"[HTTP] {httpEvent.HttpMethod} {httpEvent.Url}");
Log.Info($"[HTTP] {httpEvent.HttpMethod} {httpEvent.Url}");
}
catch (Exception ex)
{
Console.WriteLine($"处理HTTP事件时出错: {ex.Message}");
Log.Info($"处理HTTP事件时出错: {ex.Message}");
}
}
@@ -255,7 +256,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"更新进程信息时出错: {ex.Message}");
Log.Info($"更新进程信息时出错: {ex.Message}");
}
}
@@ -291,7 +292,7 @@ public class EnhancedEtwNetworkManager : IDisposable
catch (Exception ex)
{
// 进程可能已经退出
Console.WriteLine($"获取进程 {processInfo.ProcessId} 信息失败: {ex.Message}");
Log.Info($"获取进程 {processInfo.ProcessId} 信息失败: {ex.Message}");
processInfo.NeedsUpdate = false;
}
}
@@ -300,7 +301,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"处理应用程序信息时出错: {ex.Message}");
Log.Info($"处理应用程序信息时出错: {ex.Message}");
}
}
}
@@ -344,7 +345,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"处理DNS查询时出错: {ex.Message}");
Log.Info($"处理DNS查询时出错: {ex.Message}");
}
}
}
@@ -367,7 +368,7 @@ public class EnhancedEtwNetworkManager : IDisposable
{
GlobalNetworkMonitor.Instance.RemoveConnection(conn.ConnectionKey);
// 这里可以添加清理逻辑
Console.WriteLine(
Log.Info(
$"清理过期连接: {app.ProgramInfo?.ProductName} - {conn.RemoteIp}:{conn.RemotePort}");
}
}
@@ -376,7 +377,7 @@ public class EnhancedEtwNetworkManager : IDisposable
}
catch (Exception ex)
{
Console.WriteLine($"清理过期数据时出错: {ex.Message}");
Log.Info($"清理过期数据时出错: {ex.Message}");
}
}
}
@@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;
using System.Text.Json;
using Common.Logger;
using Common.Utils;
using Utils.ETW.Core;
@@ -15,7 +16,7 @@ public class NetworkMonitorUsageExample
public void RunExample()
{
Console.WriteLine("启动网络监控系统...");
Log.Info("启动网络监控系统...");
// 初始化网络管理器
_networkManager = new EnhancedEtwNetworkManager();
@@ -32,7 +33,7 @@ public class NetworkMonitorUsageExample
// 启动WebSocket推送任务(示例)
// var websocketTask = Task.Run(() => SimulateWebSocketPush(_cancellationTokenSource.Token));
// Console.WriteLine("网络监控已启动,按任意键停止...");
// Log.Info("网络监控已启动,按任意键停止...");
// Console.ReadKey();
//
// // 停止监控
@@ -42,7 +43,7 @@ public class NetworkMonitorUsageExample
finally
{
// _networkManager?.Dispose();
// Console.WriteLine("网络监控已停止!!!!!!!!!!!!!11!!!!");
// Log.Info("网络监控已停止!!!!!!!!!!!!!11!!!!");
}
}
@@ -59,26 +60,26 @@ public class NetworkMonitorUsageExample
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
var serialize = JsonHelper.ToJson(snapshot);
Console.WriteLine("=================================================");
Console.WriteLine(serialize);
Console.WriteLine("=================================================");
Log.Info("=================================================");
Log.Info(serialize);
Log.Info("=================================================");
// 输出概要信息
Console.WriteLine($"\n========== 网络监控快照 {snapshot.SnapshotTime:yyyy-MM-dd HH:mm:ss} ==========");
Console.WriteLine($"活跃应用程序: {snapshot.GlobalStats.TotalApplications}");
Console.WriteLine(
Log.Info($"\n========== 网络监控快照 {snapshot.SnapshotTime:yyyy-MM-dd HH:mm:ss} ==========");
Log.Info($"活跃应用程序: {snapshot.GlobalStats.TotalApplications}");
Log.Info(
$"总连接数: {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(
// Log.Info($"\n应用程序: {app.ApplicationName} (PID: {app.ProcessId})");
// Log.Info($" 路径: {app.ApplicationPath}");
// Log.Info($" 版本: {app.Version}");
// Log.Info($" 连接数: {app.ActiveConnections}/{app.TotalConnections}");
// Log.Info(
// $" 总流量: 发送 {FormatBytes(app.TotalBytesSent)}, 接收 {FormatBytes(app.TotalBytesReceived)}");
// Console.WriteLine(
// Log.Info(
// $" 当前速度: ↑{FormatSpeed(app.TotalSendSpeed)} ↓{FormatSpeed(app.TotalReceiveSpeed)}");
//
// // 显示前5个活跃连接
@@ -89,7 +90,7 @@ public class NetworkMonitorUsageExample
//
// foreach (var conn in topConnections)
// {
// Console.WriteLine(
// Log.Info(
// $" → {conn.Protocol} {conn.LocalPort} → {conn.RemoteIp}:{conn.RemotePort} " +
// $"({conn.RemoteDomain ?? "未解析"}) " +
// $"[{conn.State}] " +
@@ -98,24 +99,24 @@ public class NetworkMonitorUsageExample
// }
//
// // 输出端口流量TOP 5
// Console.WriteLine("\n端口流量 TOP 5:");
// Log.Info("\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)} " +
// Log.Info($" 端口 {port.Port}: {FormatBytes(port.TotalBytes)} " +
// $"(发送: {FormatBytes(port.BytesSent)}, 接收: {FormatBytes(port.BytesReceived)})");
// }
//
// // 输出IP流量TOP 5
// Console.WriteLine("\nIP流量 TOP 5:");
// Log.Info("\nIP流量 TOP 5:");
// var topIps = snapshot.GlobalStats.IpTraffic.Take(5);
//
// foreach (var ip in topIps)
// {
// Console.WriteLine($" {ip.IpAddress}: {FormatBytes(ip.TotalBytes)} " +
// Log.Info($" {ip.IpAddress}: {FormatBytes(ip.TotalBytes)} " +
// $"(发送: {FormatBytes(ip.BytesSent)}, 接收: {FormatBytes(ip.BytesReceived)})");
// }
@@ -123,7 +124,7 @@ public class NetworkMonitorUsageExample
}
catch (Exception ex)
{
Console.WriteLine($"读取网络数据时出错: {ex.Message}");
Log.Info($"读取网络数据时出错: {ex.Message}");
}
}
}
@@ -187,13 +188,13 @@ public class NetworkMonitorUsageExample
//
// // 这里应该通过WebSocket发送数据
// // await websocketClient.SendAsync(json);
// Console.WriteLine($"\n[WebSocket模拟] 推送数据大小: {json.Length} 字节");
// Console.WriteLine(json);
// Log.Info($"\n[WebSocket模拟] 推送数据大小: {json.Length} 字节");
// Log.Info(json);
// await Task.Delay(1000, cancellationToken); // 每秒推送一次
// }
// catch (Exception ex)
// {
// Console.WriteLine($"WebSocket推送时出错: {ex.Message}");
// Log.Info($"WebSocket推送时出错: {ex.Message}");
// }
// }
// }
@@ -67,8 +67,8 @@ public class TcpTracker : INetTracker
/// <param name="tcpEvent"></param>
public void ProcessTcpEvent(TcpConnectionEventData tcpEvent)
{
Console.WriteLine($"[TCP] {tcpEvent.EventType}: {tcpEvent.SourceIp}:{tcpEvent.SourcePort} -> " +
$"{tcpEvent.DestinationIp}:{tcpEvent.DestinationPort} ({tcpEvent.ProcessName})");
Log.Info($"[TCP] {tcpEvent.EventType}: {tcpEvent.SourceIp}:{tcpEvent.SourcePort} -> " +
$"{tcpEvent.DestinationIp}:{tcpEvent.DestinationPort} ({tcpEvent.ProcessName})");
switch (tcpEvent.EventType)
{
@@ -277,21 +277,21 @@ public class TcpTracker : INetTracker
// 1. 安全检查
// if (IsExternalConnection(session.DestinationIp))
// {
// Console.WriteLine(
// Log.Info(
// $"[SECURITY] 外部连接警告: {session.ProcessName} -> {session.DestinationIp}:{session.DestinationPort}");
// }
// 2. 业务监控
// if (IsBusinessCriticalPort(session.DestinationPort))
// {
// Console.WriteLine($"[BUSINESS] 关键业务连接: {session.ProcessName} -> {session.DestinationPort}");
// Log.Info($"[BUSINESS] 关键业务连接: {session.ProcessName} -> {session.DestinationPort}");
// }
// 3. 性能监控
var tcpSize = NetworkInfoManger.Instance.GetTcpSize();
if (tcpSize > 1000)
{
Console.WriteLine($"[PERFORMANCE] 连接数量警告: 当前活跃连接 {tcpSize}");
Log.Info($"[PERFORMANCE] 连接数量警告: 当前活跃连接 {tcpSize}");
}
}
@@ -341,4 +341,4 @@ public class TcpTracker : INetTracker
.Where(s => s.Duration > threshold)
.ToList();
}
}
}