using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Diagnostics;
namespace Rainbow.Services;
/// <summary>Windows 适配器。基础 CRUD 能力,系统信息采集用 .NET 内置 API + P/Invoke</summary>
public class WindowsAdapter : IOSAdapter
{
#region P/Invoke
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean GetSystemTimes(out FILETIME idleTime, out FILETIME kernelTime, out FILETIME userTime);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern Boolean GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer);
[StructLayout(LayoutKind.Sequential)]
private struct FILETIME
{
public UInt32 Low;
public UInt32 High;
public UInt64 ToUInt64() => ((UInt64)High << 32) | Low;
}
[StructLayout(LayoutKind.Sequential)]
private struct MEMORYSTATUSEX
{
public UInt32 Length;
public UInt32 MemoryLoad;
public UInt64 TotalPhys;
public UInt64 AvailPhys;
public UInt64 TotalPageFile;
public UInt64 AvailPageFile;
public UInt64 TotalVirtual;
public UInt64 AvailVirtual;
public UInt64 AvailExtendedVirtual;
}
#endregion
// CPU 计算的缓存状态
private UInt64 _prevIdle;
private UInt64 _prevKernel;
private UInt64 _prevUser;
private DateTime _prevCpuTime;
/// <summary>平台名称</summary>
public String Platform => "Windows";
/// <summary>获取系统信息</summary>
public SystemInfo GetSystemInfo() => new()
{
CpuUsage = GetCpuUsage(),
MemoryUsed = GetMemoryUsed(),
MemoryTotal = GetMemoryTotal(),
UptimeSeconds = GetUptimeSeconds(),
ConnectionCount = GetConnectionCount(),
};
/// <summary>获取功能支持度。Windows 支持基础网络功能,不支持 Linux 特有功能</summary>
public Dictionary<String, Boolean> GetCapabilities() => new()
{
["pppoe"] = false, // 通过 rasdial 可拨号,但非原生 PPPoE 服务
["dhcp"] = true, // Windows DHCP Server 服务
["dnsmasq"] = false, // 无 dnsmasq
["iptables"] = false,// 使用 netsh advfirewall
["iproute2"] = false,// 使用 route 命令
["wireguard"] = false,
["vlan"] = false, // 通过 Hyper-V 虚拟交换机
["dpi"] = false,
["ids"] = false,
};
/// <summary>CPU 使用率(0-100)。通过 P/Invoke GetSystemTimes 计算间隔差异</summary>
public Double GetCpuUsage()
{
if (!GetSystemTimes(out var idle, out var kernel, out var user))
return 0;
var now = DateTime.UtcNow;
var idleVal = idle.ToUInt64();
var kernelVal = kernel.ToUInt64();
var userVal = user.ToUInt64();
// 首次调用时缓存并返回 0
if (_prevCpuTime == default)
{
_prevIdle = idleVal;
_prevKernel = kernelVal;
_prevUser = userVal;
_prevCpuTime = now;
return 0;
}
var elapsed = (now - _prevCpuTime).TotalMilliseconds;
if (elapsed <= 0) return 0;
var idleDelta = idleVal - _prevIdle;
var kernelDelta = kernelVal - _prevKernel;
var userDelta = userVal - _prevUser;
var totalDelta = kernelDelta + userDelta;
_prevIdle = idleVal;
_prevKernel = kernelVal;
_prevUser = userVal;
_prevCpuTime = now;
if (totalDelta == 0) return 0;
return Math.Round((1 - (Double)idleDelta / totalDelta) * 100, 1);
}
/// <summary>内存使用率(0-100)。通过 P/Invoke GlobalMemoryStatusEx 获取</summary>
public Double GetMemoryUsage()
{
var stat = new MEMORYSTATUSEX();
stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
if (!GlobalMemoryStatusEx(ref stat))
return 0;
return stat.MemoryLoad;
}
/// <summary>已用内存(字节)</summary>
public Int64 GetMemoryUsed()
{
var stat = new MEMORYSTATUSEX();
stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
if (!GlobalMemoryStatusEx(ref stat))
return 0;
return (Int64)(stat.TotalPhys - stat.AvailPhys);
}
/// <summary>总内存(字节)</summary>
public Int64 GetMemoryTotal()
{
var stat = new MEMORYSTATUSEX();
stat.Length = (UInt32)System.Runtime.InteropServices.Marshal.SizeOf(stat);
if (!GlobalMemoryStatusEx(ref stat))
return 0;
return (Int64)stat.TotalPhys;
}
/// <summary>磁盘使用率</summary>
public Double GetDiskUsage()
{
try
{
var drives = DriveInfo.GetDrives();
var root = drives.FirstOrDefault(d => d.IsReady && d.Name == "C:\\");
if (root != null && root.TotalSize > 0)
return Math.Round((1 - (Double)root.AvailableFreeSpace / root.TotalSize) * 100, 1);
}
catch { }
return 0;
}
/// <summary>运行时间。使用 Environment.TickCount64</summary>
public Int64 GetUptimeSeconds() => NewLife.Runtime.TickCount64 / 1000;
/// <summary>连接数。通过 netstat -an 解析 ESTABLISHED 状态连接</summary>
public Int32 GetConnectionCount()
{
try
{
var psi = new ProcessStartInfo("netstat", "-an")
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
};
using var proc = Process.Start(psi);
if (proc == null) return 0;
var output = proc.StandardOutput.ReadToEnd();
proc.WaitForExit(5000);
var count = 0;
foreach (var line in output.Split('\n'))
{
var trimmed = line.Trim();
// 匹配 ESTABLISHED 状态连接(忽略 [::1] 等 IPv6 回环)
if (trimmed.Contains("ESTABLISHED") && !trimmed.Contains("[::1]"))
count++;
}
return count;
}
catch
{
return 0;
}
}
}
|