ASP.NET 任务管理器

最近需要做一个网页动态展示服务器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什么的。

 

最后上个图

120020_wjOq_1583678.png

转载于:https://my.oschina.net/propagator/blog/851706

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值