Windows为开发者开放了各式各样的接口,以便于实现对接系统管理、配置查看和变更、性能数据获取等功能,而由于.Net和Windows之间天生具备的紧密联系,使得相关功能的集成度更高,能比其它第三方的开发环境更轻松地实现这些接口的调用。下面会演示如何:
- 通过System.Management.ManagementObjectSearcher类获取CPU使用率(wmi);
- 通过Microsoft.VisualBasic.Devices.ComputerInfo获取系统的可用内存和总内存;
- 通过System.Net.NetworkInformation.NetworkInterface获取网卡;
- 使用PerformanceCounter获取网卡上下行流量;
- 通过System.Management.ManagementObject对象按指定的路径获取电脑各分区情况(wmi)。
因为本系列的目的在于如何获得系统的性能数据,所以相关度不是很高的信息不会花费精力去讲述如何获取。当然,如果现实中碰到了这样的需求,绝大部分也可以依靠以上渠道进行获取。
* 在这先插一个如何快速准确定位自己的物理网卡的小技巧,想知道为什么会有这种需求,可以在命令提示符窗口输入ipconfig,这时可以发现获取系统网卡时,返回的网卡列表里会包含所有列出来的无线、物理、蓝牙、甚至各种VPN或ADSL拨号的网络连接。要通过程序区分这些连接,将会是一项比较烦琐的任务。
这个方法的原理是:使用一个TcpClient向外网资源建立一个网络连接(比如连接某个网站的443端口,或某台POP3服务器的110端口),建立完成后,即可获取到TcpClient所用Socket的本地IP地址,这个地址一定是访问外网所用的网卡的IP,绝无可能出错。然后再遍历本地所有网卡,谁的IP和TcpClient的本地IP一致,谁就是外网网卡。
class Program
{
static void Main(string[] args)
{
ManagementObjectSearcher searcher;
ManagementClass disksClass = new ManagementClass("Win32_Volume");
//通过访问百度来获取Socket本地IP,再遍历本地网卡,
//定位到网卡IP与Socket本地IP一致的那块网卡,即是外网网卡。
TcpClient client = new TcpClient();
client.BeginConnect("www.baidu.com", 443, null, null);
Thread.Sleep(2000);
string ip = ((IPEndPoint)client.Client.LocalEndPoint).Address.ToString();
var adapter =
NetworkInterface.GetAllNetworkInterfaces().
First(n => n.GetIPProperties().UnicastAddresses.Any(i => i.Address.ToString() == ip));
client.Close();
PerformanceCounter speedIn =
new PerformanceCounter("Network Interface", "Bytes Received/sec", adapter.Description);
PerformanceCounter speedOut =
new PerformanceCounter("Network Interface", "Bytes Sent/sec", adapter.Description);
while (true)
{
Console.Clear();
Console.WriteLine("分区使用情况:");
ManagementObjectCollection disks = disksClass.GetInstances();
foreach (ManagementObject disk in disks)
{
string volName = disk["DriveLetter"]?.ToString();
if (string.IsNullOrEmpty(volName)) continue;
Console.WriteLine(
$"{volName}\tFileSystem: {disk["FileSystem"]}]" +
$"\t剩余:{(Convert.ToDouble(disk["FreeSpace"]) / Math.Pow(2, 30)).ToString("0.00")}GB " +
$"of {(Convert.ToDouble(disk["Capacity"]) / Math.Pow(2, 30)).ToString("0.00")}GB");
}
Console.WriteLine("\r\n网卡流量情况:");
double inMB = speedIn.NextValue() / Math.Pow(2, 20);
double outMB = speedOut.NextValue() / Math.Pow(2, 20);
Console.WriteLine(
$"速度\tin: {inMB.ToString("0.00")} MB/s, " +
$"out: {outMB.ToString("0.00")} MB/s, " +
$"total {(inMB + outMB).ToString("0.00")} MB/s");
searcher =
new ManagementObjectSearcher("select * from Win32_Processor");
foreach (ManagementObject cpu in searcher.Get())
{
var clock = ((uint)cpu["CurrentClockSpeed"]) / 1000.0;
Console.WriteLine($"\r\n{cpu["DeviceID"]}, {cpu["NumberOfCores"]}核{cpu["ThreadCount"]}线程," +
$"频率{clock.ToString("0.00GHz")},使用率: {cpu["LoadPercentage"]}% ");
}
Microsoft.VisualBasic.Devices.ComputerInfo myInfo =
new Microsoft.VisualBasic.Devices.Computer().Info;
double memoryFree = myInfo.AvailablePhysicalMemory >> 20;
double memoryTotal = myInfo.TotalPhysicalMemory >> 20;
Console.WriteLine(
$"\r\n内存:\t总容量: {memoryTotal}M\t剩余: {memoryFree}M\t已使用: {memoryTotal - memoryFree}M " +
$"({(1 - memoryFree * 1.0 / memoryTotal).ToString("0.00%")})");
Thread.Sleep(2000);
}
}
}