补充缺失文件
This commit is contained in:
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user