由於WebSocket允許保持長串連,因此當建立串連後伺服器可以主動地向Client發送相關資訊.下面通過服務端擷取當前CPU的使用方式主動發送給網頁,讓網頁即時顯示CPU使用方式的曲線圖.該案例的主要功能是包括服務端擷取CPU使和情況和HTML5使用canvas進行曲線圖繪製.
應用效果
實現效果主要是模仿windows的工作管理員,顯示每個核的工作情況.
C#擷取CPU使用方式
可能通過PerformanceCounter來擷取具本CPU線程的使用方式,不過在構建PerformanceCounter前先擷取到CPU對應的線程數量.擷取這個數量可以通過Environment.ProcessorCount屬性擷取,然後遍曆構建每個PerformanceCounter
int coreCount = Environment.ProcessorCount; for (int i = 0; i < coreCount; i++) { mCounters.Add(new PerformanceCounter("Processor", "% Processor Time", i.ToString())); }
為了方便計數器的處理,簡單地封裝了一個基礎類,完整代碼如下:
/// <summary> /// Copyright henryfan 2012 ///Email:henryfan@msn.com ///HomePage:http://www.ikende.com ///CreateTime:2012/12/24 15:10:44 /// </summary> public class ProcessorCounter { private List<PerformanceCounter> mCounters = new List<PerformanceCounter>(); public IList<PerformanceCounter> Counters { get { return mCounters; } } public void Open() { int coreCount = Environment.ProcessorCount; for (int i = 0; i < coreCount; i++) { mCounters.Add(new PerformanceCounter("Processor", "% Processor Time", i.ToString())); } } public ItemUsage[] GetValues() { ItemUsage[] values = new ItemUsage[mCounters.Count]; for (int i = 0; i < mCounters.Count; i++) { values[i] = new ItemUsage(); values[i].ID = i.ToString(); values[i].Name = "CPU " +i.ToString(); values[i].Percent = mCounters[i].NextValue(); } return values; } } public class ItemUsage { public string Name { get; set; } public float Percent { get; set; } public string ID { get; set; } }
這樣一個用於統計CPU所有線程使用方式計數的類就完成了.
頁面繪製處理
首先定義一些簡單的處理結構
function ProcessorInfo() { this.Item = null; this.Points = new Array(); for (var i = 0; i < 50; i++) { this.Points.push(new Point(0, 0)); } } function Point(x, y) { this.X = x; this.Y = y; }
主要定義線程資訊結構,預設初始化50個座標,當在接收服務線程使用方式的時候,構建一個點添加到數組件尾部同時把第一個移走.通過定時繪製這50個點的曲線這樣一個動態走勢就可以完成了.
function drawProceessor(item) { var canvas = document.getElementById('processimg' + item.Item.ID); var context = canvas.getContext('2d'); context.beginPath(); context.rect(0, 0, 200, 110); context.fillStyle = 'black'; context.fill(); context.lineWidth = 2; context.strokeStyle = 'white'; context.stroke(); context.beginPath(); context.moveTo(2, 106); for (var i = 0; i < item.Points.length; i++) { context.lineTo(4 * i + 2, 110 - item.Points[i].Y - 4); } context.lineTo(200, 106); context.closePath(); context.lineWidth = 1; context.fillStyle = '#7FFF00'; context.fill(); context.strokeStyle = '#7CFC00'; context.stroke(); context.font = '12pt Calibri'; context.fillStyle = 'white'; context.fillText(item.Item.Name, 60, 20); } function addUploadItem(info) { if (cpus[info.ID] == null) { var pinfo = new ProcessorInfo(); pinfo.Item = info; $('<canvas id="processimg' + info.ID + '" width="200" height="110"></canvas>').appendTo($('#lstProcessors')); cpus[info.ID] = pinfo; processors.push(pinfo); pinfo.Points.shift(); pinfo.Points.push(new Point(0, info.Percent)); drawProceessor(pinfo); } else { var pinfo = cpus[info.ID]; pinfo.Points.shift(); pinfo.Points.push(new Point(0, info.Percent)); } }
只需要通過定時器來不停地更新線程使用繪製即可.
setInterval(function () { for (var i = 0; i < processors.length; i++) { drawProceessor(processors[i]); } }, 1000);服務端
對於服務端其實可以根據自己的需要來使用websocket協議實現,.net 4.5也提供相應的封裝.而這裡則使用了beetle對應websocket的擴充協議包,整體代碼如下:
class Program : WebSocketJsonServer { static void Main(string[] args) { TcpUtils.Setup("beetle"); Program server = new Program(); server.Open(8070); Console.WriteLine("websocket start@8070"); ProcessorCounter counters = new ProcessorCounter(); counters.Open(); while (true) { ItemUsage[] items = counters.GetValues(); foreach (ItemUsage item in items) { Console.WriteLine("{0}:{1}%", item.Name, item.Percent); } JsonMessage message = new JsonMessage(); message.type = "cpu useage"; message.data = items; foreach (TcpChannel channel in server.Server.GetOnlines()) { channel.Send(message); } System.Threading.Thread.Sleep(995); } System.Threading.Thread.Sleep(-1); } protected override void OnError(object sender, ChannelErrorEventArgs e) { base.OnError(sender, e); Console.WriteLine(e.Exception.Message); } protected override void OnConnected(object sender, ChannelEventArgs e) { base.OnConnected(sender, e); Console.WriteLine("{0} connected", e.Channel.EndPoint); } protected override void OnDisposed(object sender, ChannelDisposedEventArgs e) { base.OnDisposed(sender, e); Console.WriteLine("{0} disposed", e.Channel.EndPoint); } }
每秒擷取一次CPU的使用方式,並把資訊以json的方式發送給當前所有線上的串連.
下載
完整代碼:ProcessorsMonitor.rar (686.02 kb)
示範地址:http://html5.ikende.com/ProcessorsMonitor.htm (瀏覽器使用chrome或IE10)