由于WebSocket允许保持长连接,因此当建立连接后服务器可以主动地向Client发送相关信息.下面通过服务端获取当前CPU的使用情况主动发送给网页,让网页实时显示CPU使用情况的曲线图.该事例的主要功能是包括服务端获取CPU使和情况和HTML5使用canvas进行曲线图绘制.
应用效果
实现效果主要是模仿windows的任务管理器,显示每个核的工作情况.
C#获取CPU使用情况
可能通过PerformanceCounter来获取具本CPU线程的使用情况,不过在构建PerformanceCounter前先获取到CPU对应的线程数量.获取这个数量可以通过Environment.ProcessorCount属性获取,然后遍历构建每个PerformanceCounter
1
2
3
4
5
|
int
coreCount = Environment.ProcessorCount;
for
(
int
i = 0; i < coreCount; i++)
{
mCounters.Add(
new
PerformanceCounter(
"Processor"
,
"% Processor Time"
, i.ToString()));
}
|
为了方便计数器的处理,简单地封装了一个基础类,完整代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
/// <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所有线程使用情况计数的类就完成了.
页面绘制处理
首先定义一些简单的处理结构
1
2
3
4
5
6
7
8
9
10
11
|
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个点的曲线这样一个动态的走势就可以完成了.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
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));
}
}
|
只需要通过定时器来不停地更新线程使用绘制即可.
1
2
3
4
5
|
setInterval(
function
() {
for
(
var
i = 0; i < processors.length; i++) {
drawProceessor(processors[i]);
}
}, 1000);
|
服务端
对于服务端其实可以根据自己的需要来使用websocket协议实现,.net 4.5也提供相应的封装.而这里则使用了beetle对应websocket的扩展协议包,整体代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
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)