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,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;
}
}
}