补充缺失文件

This commit is contained in:
jimmy committed 2025-08-08 10:32:53 +08:00
1 parent 8e67d345aa
commit bc2a826008
2 files changed
+472

No files matched your search

@@ -0,0 +1,181 @@
using Utils.ETW.Etw;
namespace Utils.ETW.Models;
/// <summary>
/// 进程网络统计信息
/// </summary>
public class ProcessNetworkStats
{
/// <summary>
/// 进程ID
/// </summary>
public int ProcessId { get; set; }
/// <summary>
/// 进程名称
/// </summary>
public string ProcessName { get; set; } = string.Empty;
/// <summary>
/// 应用程序信息
/// </summary>
public ApplicationInfo? ApplicationInfo { get; set; }
/// <summary>
/// 当前上传速度 (字节/秒)
/// </summary>
public double CurrentUploadSpeed { get; set; }
/// <summary>
/// 当前下载速度 (字节/秒)
/// </summary>
public double CurrentDownloadSpeed { get; set; }
/// <summary>
/// 总网速 (上传+下载) (字节/秒)
/// </summary>
public double TotalSpeed => CurrentUploadSpeed + CurrentDownloadSpeed;
/// <summary>
/// 格式化的上传速度
/// </summary>
public string FormattedUploadSpeed => FormatSpeed(CurrentUploadSpeed);
/// <summary>
/// 格式化的下载速度
/// </summary>
public string FormattedDownloadSpeed => FormatSpeed(CurrentDownloadSpeed);
/// <summary>
/// 格式化的总速度
/// </summary>
public string FormattedTotalSpeed => FormatSpeed(TotalSpeed);
/// <summary>
/// 上次更新时间
/// </summary>
public DateTime LastUpdateTime { get; set; } = DateTime.Now;
/// <summary>
/// 活跃连接数
/// </summary>
public int ActiveConnectionCount { get; set; }
/// <summary>
/// 格式化网速显示 - 固定4字符宽度
/// </summary>
private static string FormatSpeed(double bytesPerSecond)
{
if (bytesPerSecond == 0)
return "0 B";
// 确定单位和数值
string unit;
double value;
if (bytesPerSecond >= 1024 * 1024 * 1024) // >= 1GB
{
value = bytesPerSecond / (1024 * 1024 * 1024);
unit = "GB";
}
else if (bytesPerSecond >= 1024 * 1024) // >= 1MB
{
value = bytesPerSecond / (1024 * 1024);
unit = "MB";
}
else if (bytesPerSecond >= 1024) // >= 1KB
{
value = bytesPerSecond / 1024;
unit = "KB";
}
else // < 1KB
{
value = bytesPerSecond;
unit = "B";
}
// 格式化为4字符(不包含单位)
string numStr;
if (value >= 1000) // >= 1000,只显示整数
{
numStr = ((int)Math.Round(value)).ToString();
}
else if (value >= 100) // 100-999,显示1位小数或整数
{
if (value % 1 < 0.1) // 基本是整数
numStr = ((int)value).ToString();
else
numStr = value.ToString("F1");
}
else if (value >= 10) // 10-99,显示1-2位小数
{
if (value % 1 < 0.01) // 基本是整数
numStr = value.ToString("F0");
else if (value % 1 < 0.1) // 只需1位小数
numStr = value.ToString("F1");
else
numStr = value.ToString("F2");
}
else // < 10,显示2位小数
{
numStr = value.ToString("F2");
}
// 确保数字部分不超过4个字符
if (numStr.Length > 4)
{
if (numStr.Contains('.'))
{
// 有小数点,尝试减少小数位数
var parts = numStr.Split('.');
var integerPart = parts[0];
var decimalPart = parts[1];
if (integerPart.Length >= 4)
{
// 整数部分已经4位或以上,不要小数
numStr = integerPart.Substring(0, 4);
}
else
{
// 调整小数位数
var maxDecimalDigits = 3 - integerPart.Length; // 减去小数点占用的1位
if (maxDecimalDigits > 0 && decimalPart.Length > maxDecimalDigits)
{
decimalPart = decimalPart.Substring(0, maxDecimalDigits);
numStr = $"{integerPart}.{decimalPart}";
}
}
}
else
{
// 没有小数点,截断到4位
numStr = numStr.Substring(0, 4);
}
}
return $"{numStr,4}{unit}";
}
}
/// <summary>
/// 网速Top榜信息
/// </summary>
public class NetworkTopListInfo
{
/// <summary>
/// Top进程列表
/// </summary>
public List<ProcessNetworkStats> TopProcesses { get; set; } = new();
/// <summary>
/// 更新时间
/// </summary>
public DateTime UpdateTime { get; set; } = DateTime.Now;
/// <summary>
/// 是否有数据(现在总是有数据,因为确保固定数量的显示)
/// </summary>
public bool HasData => TopProcesses.Count > 0;
}
@@ -0,0 +1,291 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using Utils.ETW.Etw;
using Utils.ETW.Models;
namespace Utils.ETW.Services;
/// <summary>
/// 网速Top榜管理器
/// 负责计算和维护各进程的网络速度统计
/// </summary>
public class NetworkTopListManager
{
private static readonly Lazy<NetworkTopListManager> _instance = new(() => new NetworkTopListManager());
public static NetworkTopListManager Instance => _instance.Value;
/// <summary>
/// 进程网络统计信息缓存
/// </summary>
private readonly ConcurrentDictionary<int, ProcessNetworkStats> _processStats = new();
/// <summary>
/// 上次统计时间戳
/// </summary>
private readonly ConcurrentDictionary<int, DateTime> _lastCalculationTime = new();
/// <summary>
/// 上次流量数据
/// </summary>
private readonly ConcurrentDictionary<int, (long TotalSent, long TotalReceived)> _lastTrafficData = new();
/// <summary>
/// 读写锁
/// </summary>
private readonly ReaderWriterLockSlim _lock = new();
/// <summary>
/// 统计更新间隔 (秒)
/// </summary>
private const double UPDATE_INTERVAL_SECONDS = 1.0;
private NetworkTopListManager()
{
// 初始化
}
/// <summary>
/// 更新所有进程的网络统计
/// </summary>
public void UpdateAllProcessStats()
{
_lock.EnterWriteLock();
try
{
var snapshot = GlobalNetworkMonitor.Instance.GetSnapshot();
var currentTime = DateTime.Now;
// 更新每个应用程序的统计信息
foreach (var app in snapshot.Applications)
{
UpdateProcessStats(app, currentTime);
}
// 清理不活跃的进程统计
CleanupInactiveProcesses(currentTime);
}
finally
{
_lock.ExitWriteLock();
}
}
/// <summary>
/// 更新单个进程的统计信息
/// </summary>
private void UpdateProcessStats(ApplicationSnapshot app, DateTime currentTime)
{
var processId = app.ProcessId;
// 获取当前的总流量
var currentTotalSent = app.TotalBytesSent;
var currentTotalReceived = app.TotalBytesReceived;
// 检查是否有之前的数据用于计算速度
if (_lastTrafficData.TryGetValue(processId, out var lastTraffic) &&
_lastCalculationTime.TryGetValue(processId, out var lastTime))
{
var timeDiff = (currentTime - lastTime).TotalSeconds;
if (timeDiff >= UPDATE_INTERVAL_SECONDS)
{
// 计算速度
var uploadSpeed = Math.Max(0, (currentTotalSent - lastTraffic.TotalSent) / timeDiff);
var downloadSpeed = Math.Max(0, (currentTotalReceived - lastTraffic.TotalReceived) / timeDiff);
// 更新或创建统计信息
_processStats.AddOrUpdate(processId,
new ProcessNetworkStats
{
ProcessId = processId,
ProcessName = GetProcessName(processId),
ApplicationInfo = GetApplicationInfo(app),
CurrentUploadSpeed = uploadSpeed,
CurrentDownloadSpeed = downloadSpeed,
LastUpdateTime = currentTime,
ActiveConnectionCount = app.ActiveConnections
},
(key, existing) =>
{
existing.CurrentUploadSpeed = uploadSpeed;
existing.CurrentDownloadSpeed = downloadSpeed;
existing.LastUpdateTime = currentTime;
existing.ActiveConnectionCount = app.ActiveConnections;
existing.ApplicationInfo = GetApplicationInfo(app);
return existing;
});
// 更新缓存数据
_lastTrafficData[processId] = (currentTotalSent, currentTotalReceived);
_lastCalculationTime[processId] = currentTime;
}
}
else
{
// 首次记录,初始化数据
_lastTrafficData[processId] = (currentTotalSent, currentTotalReceived);
_lastCalculationTime[processId] = currentTime;
// 创建初始统计信息(速度为0)
_processStats[processId] = new ProcessNetworkStats
{
ProcessId = processId,
ProcessName = GetProcessName(processId),
ApplicationInfo = GetApplicationInfo(app),
CurrentUploadSpeed = 0,
CurrentDownloadSpeed = 0,
LastUpdateTime = currentTime,
ActiveConnectionCount = app.ActiveConnections
};
}
}
/// <summary>
/// 获取应用程序信息
/// </summary>
private ApplicationInfo? GetApplicationInfo(ApplicationSnapshot app)
{
if (app.ProgramInfo != null)
{
return new ApplicationInfo
{
ProcessId = app.ProcessId,
ProgramInfo = app.ProgramInfo,
FirstSeenTime = app.FirstSeenTime,
LastUpdateTime = app.LastActiveTime
};
}
return null;
}
/// <summary>
/// 获取进程名称
/// </summary>
private string GetProcessName(int processId)
{
try
{
using var process = Process.GetProcessById(processId);
return process.ProcessName;
}
catch
{
return $"Process_{processId}";
}
}
/// <summary>
/// 清理不活跃的进程统计
/// </summary>
private void CleanupInactiveProcesses(DateTime currentTime)
{
var inactiveThreshold = TimeSpan.FromMinutes(5); // 5分钟无活动的进程将被清理
var processesToRemove = _processStats
.Where(kvp => currentTime - kvp.Value.LastUpdateTime > inactiveThreshold)
.Select(kvp => kvp.Key)
.ToList();
foreach (var processId in processesToRemove)
{
_processStats.TryRemove(processId, out _);
_lastCalculationTime.TryRemove(processId, out _);
_lastTrafficData.TryRemove(processId, out _);
}
}
/// <summary>
/// 获取网速Top榜
/// </summary>
/// <param name="count">返回的数量,最多5个</param>
/// <returns>Top榜信息</returns>
public NetworkTopListInfo GetTopList(int count = 5)
{
count = Math.Min(count, 5); // 限制最多5个
_lock.EnterReadLock();
try
{
// 先获取有网络活动的进程
var activeProcesses = _processStats.Values
.Where(p => p.TotalSpeed > 0)
.OrderByDescending(p => p.TotalSpeed)
.Take(count)
.ToList();
var topProcesses = new List<ProcessNetworkStats>(activeProcesses);
// 如果有网络活动的进程不够,用无网络活动的进程填充
if (topProcesses.Count < count)
{
var inactiveProcesses = _processStats.Values
.Where(p => p.TotalSpeed == 0)
.OrderBy(p => p.ProcessName) // 按进程名称首字母排序
.Take(count - topProcesses.Count)
.ToList();
topProcesses.AddRange(inactiveProcesses);
}
// 如果还是不够,创建占位符进程
while (topProcesses.Count < count)
{
topProcesses.Add(new ProcessNetworkStats
{
ProcessId = -1,
ProcessName = "---",
CurrentUploadSpeed = 0,
CurrentDownloadSpeed = 0,
LastUpdateTime = DateTime.Now,
ActiveConnectionCount = 0
});
}
return new NetworkTopListInfo
{
TopProcesses = topProcesses,
UpdateTime = DateTime.Now
};
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// 获取指定进程的统计信息
/// </summary>
public ProcessNetworkStats? GetProcessStats(int processId)
{
_lock.EnterReadLock();
try
{
_processStats.TryGetValue(processId, out var stats);
return stats;
}
finally
{
_lock.ExitReadLock();
}
}
/// <summary>
/// 重置所有统计数据
/// </summary>
public void Reset()
{
_lock.EnterWriteLock();
try
{
_processStats.Clear();
_lastCalculationTime.Clear();
_lastTrafficData.Clear();
}
finally
{
_lock.ExitWriteLock();
}
}
}