最近需要做一个网页动态展示服务器CPU,内存等信息,类似windows任务管理器的B/S版。因为服务器是windows server 2008,所以采用了ASP.NET来开发,主要涉及2部分,一是读取
最近需要做一个网页动态展示服务器CPU,内存等信息,类似windows任务管理器的B/S版。因为服务器是windows server 2008,所以采用了ASP.NET来开发,主要涉及2部分,一是读取系统信息;二是动态展示。
读取系统信息分为CPU,内存,硬盘和网络四部分。其中内存和硬盘信息都用了System.Management类库,CPU信息则用到了System.Diagnostics命名空间下的PerformanceCounter类,网络信息主要利用System.Net.NetworkInformation命名空间下的类。源代码如下:
public struct DiskInfo{ public string Name; public long Free; public long Size;}public class SystemInfo{ private const string CategoryName = "Processor"; private const string CounterName = "% Processor Time"; private const string InstanceName = "_Total"; private static PerformanceCounter pc = new PerformanceCounter(CategoryName, CounterName, InstanceName); private static NetworkInterface[] nicArr; //网卡集合 private static long sent = 0, received = 0; public static string NetName = ""; /// <summary> /// CPU 使用率,可参考 /// https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter(v=vs.110).aspx /// https://msdn.microsoft.com/en-us/library/w8f5kw2e(v=vs.110).aspx /// 其中CategoryName主要有如下几种 /// Cache, Memory, Objects, PhysicalDisk, Process, Processor, Server, System, Thread categories /// 而CounterName可以通过Performance Monitor查看已有的(在Performance Monitor中, /// 选中Performance Monitor,点击添加“+”,即可看到)。 /// </summary> /// <returns>CPU使用百分比</returns> public static float CPUrate() { // 单个CPU使用情况要除以CPU个数 Environment.ProcessorCount,但是windows似乎每个CPU使用率并不完全相同 return pc.NextValue(); } /// <summary> /// 机器总的内存数,注意该值可能不精确。可参考 /// https://msdn.microsoft.com/en-us/library/aa394102(v=vs.85).aspx /// 还可以使用 Win32_PhysicalMemory 类中的 Capacity 变量来获得内存信息,可参考 /// https://msdn.microsoft.com/en-us/library/aa394347(v=vs.85).aspx /// </summary> /// <returns>总内存大小字节数,单位是Bytes</returns> public static long TotalMemory() { long m_PhysicalMemory = 0; ManagementClass mc = new ManagementClass("Win32_ComputerSystem"); ManagementObjectCollection moc = mc.GetInstances(); foreach (ManagementObject mo in moc) { if (mo["TotalPhysicalMemory"] != null) { m_PhysicalMemory = long.Parse(mo["TotalPhysicalMemory"].ToString()); } } return m_PhysicalMemory; } /// <summary> /// 已用内存信息,可参考 /// https://msdn.microsoft.com/en-us/library/aa394239(v=vs.85).aspx /// </summary> /// <returns>返回已使用的内存大小,单位是Bytes</returns> public static long MemUsage() { long m_PhysicalMemory = 0; long availablebytes = 0; ManagementClass mos = new ManagementClass("Win32_OperatingSystem"); foreach (ManagementObject mo in mos.GetInstances()) { if (mo["FreePhysicalMemory"] != null) { availablebytes = 1024 * long.Parse(mo["FreePhysicalMemory"].ToString()); } if (mo["TotalVisibleMemorySize"] != null) { m_PhysicalMemory = 1024 * long.Parse(mo["TotalVisibleMemorySize"].ToString()); } } return m_PhysicalMemory - availablebytes; } /// <summary> /// 硬盘使用情况,可参考 /// https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx /// </summary> /// <returns>返回了硬盘基本信息,包括名称,大小,可用大小,单位为Bytes</returns> public static DiskInfo[] DiskUsage() { ManagementClass diskClass = new ManagementClass("Win32_LogicalDisk"); ManagementObjectCollection disks = diskClass.GetInstances(); List<DiskInfo> info = new List<DiskInfo>(); foreach (ManagementObject disk in disks) { if (int.Parse(disk["DriveType"].ToString()) == (int)DriveType.Fixed) { string name = disk["Name"].ToString(); long size = long.Parse(disk["Size"].ToString()); long free = long.Parse(disk["FreeSpace"].ToString()); info.Add(new DiskInfo() { Name = name, Size = size, Free = free }); } } return info.ToArray(); } /// <summary> /// 网络传输信息,可参考 /// https://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkinterface(v=vs.110).aspx /// </summary> /// <param name="ipAddress">要监控的ip地址</param> /// <param name="received">下载字节数,单位为Bytes</param> /// <param name="sent">上传字节数,单位为Bytes</param> public static void NetUsage(string ipAddress, out long received, out long sent) { nicArr = NetworkInterface.GetAllNetworkInterfaces(); foreach (NetworkInterface net in nicArr) { IPInterfaceProperties ipProperty = net.GetIPProperties(); // 该网卡为以太网且有连接 if (net.NetworkInterfaceType == NetworkInterfaceType.Ethernet && net.OperationalStatus == OperationalStatus.Up) { foreach (var ip in ipProperty.UnicastAddresses) { // 如果为IPv4地址 if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { NetName = ip.Address.ToString(); // 获取ip地址 } } if (NetName == ipAddress) { IPv4InterfaceStatistics curIPfs = net.GetIPv4Statistics(); info.Received = curIPfs.BytesReceived - received; info.Sent = curIPfs.BytesSent - sent; sent = curIPfs.BytesSent; received = curIPfs.BytesReceived; break; } } } }}
为了方便,把相关的几个网址记录如下:
- CPU 使用率,可参考
https://msdn.microsoft.com/en-us/library/system.diagnostics.performancecounter(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/w8f5kw2e(v=vs.110).aspx
- 内存信息,可参考
https://msdn.microsoft.com/en-us/library/aa394102(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/aa394347(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/aa394239(v=vs.85).aspx
- 硬盘使用情况,可参考
https://msdn.microsoft.com/en-us/library/aa394173(v=vs.85).aspx
- 网络传输信息,可参考
https://msdn.microsoft.com/en-us/library/system.net.networkinformation.networkinterface(v=vs.110).aspx
动态展示主要用到ASP.NET chart控件和updatepanel控件。鉴于硬盘信息变化实时性不强,因此用两个panel分别放置动态的(CPU,内存和网络)和静态的(硬盘)chart。
aspx文件主要代码如下:
<asp:Panel ID="DynamicPanel" runat="server"> <asp:ScriptManager ID="ScriptManager1" runat="server"> </asp:ScriptManager> <asp:UpdatePanel ID="UpdatePanel1" runat="server"> <ContentTemplate> <%--每2秒(2000毫秒)更新一次--%> <asp:Timer ID="timerTest" runat="server" Interval="2000" OnTick="timer_Tick"> </asp:Timer> <asp:Chart ID="Chart1" runat="server" Width="640px" Height="360px"> <Series> <asp:Series Name="Series1" ChartType="SplineArea" Color="PowderBlue" BorderColor="Blue"> </asp:Series> </Series> <ChartAreas> <asp:ChartArea Name="ChartArea1" AlignmentOrientation="Horizontal"> <AxisX> <MajorGrid LineDashStyle="Dash" /> <LabelStyle Enabled="false" /> </AxisX> <AxisY Title="Y Axis" TitleFont="微软雅黑,16pt" TitleForeColor="RoyalBlue"> <MajorGrid LineDashStyle="Dash" /> </AxisY> </asp:ChartArea> </ChartAreas> <Legends> <asp:Legend Name="Legend1" Enabled="False"></asp:Legend> </Legends> </asp:Chart> </ContentTemplate> </asp:UpdatePanel></asp:Panel><asp:Panel ID="StaticPanel" runat="server" ScrollBars="Vertical"></asp:Panel>
aspx.cs主要代码如下:
public struct NetInfo{ public long Sent; public long Received;}public partial class SysInfoChart : System.Web.UI.Page{ private static string InfoType = "cpu"; // 该变量用于记录当前状态 private static float m_timeInterval = 2; // 刷新时间,用于计算网络传输速率 private static bool m_loaded = false; // 该变量用于控制单次载入 private const int gridX = 10; // 最多显示10个数据点 public static List<float> ChartData = new List<float>(); public static List<NetInfo> NetData = new List<NetInfo>(); public static DiskInfo[] DiskData; public static int TickNum = 0; public const float GBFactor = 1024 * 1024 * 1024.0f; public const float MBFactor = 1024 * 1024.0f; public const float KBFactor = 1024.0f; public static float TotalMemory = SystemInfo.TotalMemory() / MBFactor; protected void Page_Load(object sender, EventArgs e) { if (!m_loaded) { m_timeInterval = timerTest.Interval / 1000.0f; if (InfoType == "disk") { DynamicPanel.Visible = false; StaticPanel.Visible = true; } else { DynamicPanel.Visible = true; StaticPanel.Visible = false; } TickNum = 0; ChartData.Clear(); NetData.Clear(); m_loaded = true; } } protected void timer_Tick(object sender, EventArgs e) { TickNum += 1; switch(InfoType) { case "cpu": ChartData.Add(SystemInfo.CPUrate()); CPU_Chart_Load(sender, e); break; case "mem": ChartData.Add(SystemInfo.MemUsage() / MBFactor); Mem_Chart_Load(); break; case "disk": DiskData = SystemInfo.DiskUsage(); Disk_Chart_Load(); break; case "net": long received, sent; // 此处"192.168.1.1"为本机ip地址 SystemInfo.NetUsage("192.168.1.1", out received, out sent); NetData.Add(new NetInfo(){ Received = received, Sent = sent }); Net_Chart_Load(); break; default: break; } } /// <summary> /// 调整数据,只显示固定数量的数据点。如果数据量不足,则显示0 /// 该实现不好,应该用固定大小Queue,不过时间不够,先凑合用 /// </summary> /// <param name="dt">要显示的数据表</param> private void DataLoad(ref DataTable dt) { if (ChartData.Count >= gridX) // 如果数据量多于要显示的 { int index = ChartData.Count - gridX; for (int i = 0; i < gridX; i++) { dt.Rows.Add(i, ChartData[index + i]); } } else // 如果数据量不足 { int index = gridX - ChartData.Count; for (int i = 0; i < gridX; i++) { if (i < index) { dt.Rows.Add(i, 0); } else { dt.Rows.Add(i, ChartData[i - index]); } } } } /// <summary> /// 调整数据,只显示固定数量的数据点。如果数据量不足,则显示0。专为网络数据用。 /// 将来最好和上一个函数整合一下,时间不够凑合用 /// </summary> /// <param name="dt">要显示的数据表</param> private void DataLoad2(ref DataTable dt) { if (NetData.Count >= gridX) { int index = NetData.Count - gridX; for (int i = 0; i < gridX; i++) { int tmp = index + i; float divider = KBFactor * m_timeInterval; dt.Rows.Add(i, NetData[tmp].Sent / divider, NetData[tmp].Received / divider, NetData[tmp].MaxSpeed / divider); } } else { int index = gridX - NetData.Count; for (int i = 0; i < gridX; i++) { if (i < index) { dt.Rows.Add(i, 0, 0, 0); } else { int tmp = i - index; float divider = KBFactor * m_timeInterval; dt.Rows.Add(i, NetData[tmp].Sent / divider, NetData[tmp].Received / divider, NetData[tmp].MaxSpeed / divider); } } } } protected void CPU_Chart_Load(object sender, EventArgs e) { DataTable m_dt = new DataTable(); m_dt.Columns.Add("时间", typeof(int)); m_dt.Columns.Add("CPU 占用率 (%)", typeof(float)); DataLoad(ref m_dt); Chart1.DataSource = m_dt; Chart1.Series["Series1"].XValueMember = "时间"; Chart1.Series["Series1"].YValueMembers = "CPU 占用率 (%)"; Chart1.ChartAreas["ChartArea1"].AxisY.Title = "CPU 占用率 (%)"; Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0; Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = 100; Chart1.DataBind(); } protected void Mem_Chart_Load() { DataTable m_dt = new DataTable(); m_dt.Columns.Add("时间", typeof(int)); m_dt.Columns.Add("内存占用", typeof(float)); DataLoad(ref m_dt); Chart1.DataSource = m_dt; Chart1.Series["Series1"].XValueMember = "时间"; Chart1.Series["Series1"].YValueMembers = "内存占用"; Chart1.ChartAreas["ChartArea1"].AxisY.Title = "内存占用 (MB)"; Chart1.ChartAreas["ChartArea1"].AxisY.Minimum = 0; Chart1.ChartAreas["ChartArea1"].AxisY.Maximum = TotalMemory; Chart1.ChartAreas["ChartArea1"].AxisY.LabelStyle.Format = "f2"; // 只显示2位小数 Chart1.DataBind(); } protected void Disk_Chart_Load() { for (int i = 0; i < DiskData.Length; i++) { string name = DiskData[i].Name; float used = (DiskData[i].Size - DiskData[i].Free) / GBFactor; float free = DiskData[i].Free / GBFactor; float size = DiskData[i].Size / GBFactor; List<string> dataN = new List<string>(); List<string> dataS = new List<string>(); dataN.Add("可用空间"); dataN.Add("已用空间"); dataS.Add(free.ToString("f2")); dataS.Add(used.ToString("f2")); #region 动态添加表 Chart m_chart = new Chart(); m_chart.Width = 500; m_chart.Height = 400; ChartArea m_area; Series m_series; m_area = new ChartArea("ChartArea" + i.ToString()); m_series = new Series("Series" + i.ToString()); m_chart.ChartAreas.Add(m_area); m_chart.Series.Add(m_series); Legend m_legend = new Legend("Legend" + i.ToString()); m_legend.Docking = Docking.Top; m_legend.LegendStyle = LegendStyle.Row; m_chart.Legends.Add(m_legend); Title m_title = new Title("磁盘驱动器" + name); m_title.Font = new System.Drawing.Font("微软雅黑", 16); m_title.ForeColor = System.Drawing.Color.SteelBlue; m_chart.Titles.Add(m_title); m_series.ChartType = SeriesChartType.Pie; // 饼图 m_series.ChartArea = m_area.Name; m_series.LegendText = "#VALX: #VALY GB"; m_series.Label = "#VALY GB [#PERCENT]"; m_series.Points.DataBindXY(dataN, dataS); m_series["PieLabelStyle"] = "Outside"; //饼图说明显示方式(外面) m_series.ShadowOffset = 2; m_series.BorderColor = System.Drawing.Color.DarkGray; #endregion StaticPanel.Controls.Add(m_chart); } } protected void Net_Chart_Load() { DataTable m_dt = new DataTable(); m_dt.Columns.Add("时间", typeof(int)); m_dt.Columns.Add("上传速率 (KB/s)", typeof(float)); m_dt.Columns.Add("下载速率 (KB/s)", typeof(float)); m_dt.Columns.Add("最大速率 (KB/s)", typeof(float)); DataLoad2(ref m_dt); Chart1.DataSource = m_dt; Chart1.Series["Series1"].XValueMember = "时间"; Chart1.Series["Series1"].YValueMembers = "下载速率 (KB/s)"; float downLoadRate = NetData[NetData.Count - 1].Received / (m_timeInterval * KBFactor); Chart1.Series["Series1"].LegendText = "下载速率:" + downLoadRate.ToString("f2") + " KB/s"; Series m_series = new Series("Series2"); m_series.XValueMember = "时间"; m_series.YValueMembers = "上传速率 (KB/s)"; m_series.ChartType = SeriesChartType.SplineArea; m_series.Color = System.Drawing.Color.FromArgb(128, System.Drawing.Color.LightGreen); // 半透明,防止互相遮挡 m_series.BorderColor = System.Drawing.Color.Green; Chart1.Series.Add(m_series); float upLoadRate = NetData[NetData.Count - 1].Sent / (m_timeInterval * KBFactor); Chart1.Series["Series2"].LegendText = "上传速率:" + upLoadRate.ToString("f2") + " KB/s"; Chart1.Legends["Legend1"].Enabled = true; Chart1.ChartAreas["ChartArea1"].AxisY.Title = "上传下载速率 (KB/s)"; Chart1.DataBind(); }}
最后这个aspx.cs文件做了些修改,可能会导致编译无法通过,如果直接复制过去的话,需要自己修改一下。另外有几个地方时间紧来不及好好设计实现了,凑合完成了功能,有时间可以再好好弄一下。比如网络可以根据当前传输速率自动切换单位为MB和KB什么的。
最后上个图