实战解析--项目的主要技术储备
1--通讯技术
在上篇了展望了本项目的一个框架,我们也知道:如果这个项目的处理时间不能达到要求的话,则花哨的功能也不能逃过失败的定论。
而通讯的关键在于数据处理枢纽的层数和处理中转的时间,数据枢纽下联数据采集器、上联高层数据枢纽或者监控台。数据的最长路经是:局房数据采集器-->县局数据枢纽-->市局数据枢纽-->省局数据枢纽-->监控台。则总共经历四次传送,则每次中转和处理的时间应该<2/4=500ms。
目前.Net提供比较安全的远程处理机制和Web Service,我编写一个测试程序,发现在我配置比较高的机器上一次传送100条记录的数据包的处理时间平均在400ms,看来就比较危险了。
以前我们的数据采集器连接的有智能设备;A/D单片机等,而上层的数据处理部分有跑在UNIX,所以稳妥地方式还是使用原生的socket保险些,但是这里就只能忽略了安全保证(考虑是在电信内网运行),当然传送时可以简单加密一下数据。
下面是我定义的接口:
IMonitorChannel---提供给观看者,只能收取数据,不能发送命令;
IClientChannel---主要用于监控台;
IServerChannel---主要用于数据枢纽,可以用来接收采集器的数据或者发布数据到数据订阅者
实现就很简单了,网上很多开源的Socket C#版。我就不贴了,有需要的可以邮件给我。
2--扩展技术
既然castle提供了那么强大的容器,那我就直接使用它得了。下图是传统的功能调用和基于数据队列处理的思路图,后者我已经在好几个大型项目中使用,比较容易维护和调试。
以下是所有规则处理器的祖先类:
<component id="linearity"
type="OpenMonitor.Services.LinearityFormula,ExtendRule"
lifestyle="Pooled" initialPoolSize="2" maxPoolSize="5" >
</component>
但是实际上多个和一个处理效果没有区别,第二个总会扑空的,你看出来了吗?且听我下回分解吧。
alex 11-24
在上篇了展望了本项目的一个框架,我们也知道:如果这个项目的处理时间不能达到要求的话,则花哨的功能也不能逃过失败的定论。
而通讯的关键在于数据处理枢纽的层数和处理中转的时间,数据枢纽下联数据采集器、上联高层数据枢纽或者监控台。数据的最长路经是:局房数据采集器-->县局数据枢纽-->市局数据枢纽-->省局数据枢纽-->监控台。则总共经历四次传送,则每次中转和处理的时间应该<2/4=500ms。
目前.Net提供比较安全的远程处理机制和Web Service,我编写一个测试程序,发现在我配置比较高的机器上一次传送100条记录的数据包的处理时间平均在400ms,看来就比较危险了。
以前我们的数据采集器连接的有智能设备;A/D单片机等,而上层的数据处理部分有跑在UNIX,所以稳妥地方式还是使用原生的socket保险些,但是这里就只能忽略了安全保证(考虑是在电信内网运行),当然传送时可以简单加密一下数据。
下面是我定义的接口:
1using System;
2
3namespace QPG.Net
4{
5 public delegate void StateChangedCallback(string text);
6 public delegate void DataReceivedCallback(string text,int curSocketIndex);
7
8 public interface IMonitorChannel{
9 event StateChangedCallback OnConnected;
10 event DataReceivedCallback OnReceived;
11 event StateChangedCallback OnDisconnect;
12
13 void open();
14 void close();
15
16 bool Opened {get;}
17 }
18
19 public interface IClientChannel:IMonitorChannel{
20
21 void sendMsg(string msg);
22
23 }
24
25 public interface IServerChannel:IClientChannel {
26 int Port{get;}
27
28 void sendMsgToAll(string msg);
29 void sendMsgToClient(string msg, int clientNumber);
30 }
31
32}
2
3namespace QPG.Net
4{
5 public delegate void StateChangedCallback(string text);
6 public delegate void DataReceivedCallback(string text,int curSocketIndex);
7
8 public interface IMonitorChannel{
9 event StateChangedCallback OnConnected;
10 event DataReceivedCallback OnReceived;
11 event StateChangedCallback OnDisconnect;
12
13 void open();
14 void close();
15
16 bool Opened {get;}
17 }
18
19 public interface IClientChannel:IMonitorChannel{
20
21 void sendMsg(string msg);
22
23 }
24
25 public interface IServerChannel:IClientChannel {
26 int Port{get;}
27
28 void sendMsgToAll(string msg);
29 void sendMsgToClient(string msg, int clientNumber);
30 }
31
32}
IMonitorChannel---提供给观看者,只能收取数据,不能发送命令;
IClientChannel---主要用于监控台;
IServerChannel---主要用于数据枢纽,可以用来接收采集器的数据或者发布数据到数据订阅者
实现就很简单了,网上很多开源的Socket C#版。我就不贴了,有需要的可以邮件给我。
2--扩展技术
既然castle提供了那么强大的容器,那我就直接使用它得了。下图是传统的功能调用和基于数据队列处理的思路图,后者我已经在好几个大型项目中使用,比较容易维护和调试。
以下是所有规则处理器的祖先类:
namespace OpenMonitor.Services {
using System;
using System.Collections;
using OpenMonitor.Data;
using OpenMonitor.Utility;
using OpenMonitor;
using Castle.Model;
public class BaseService:IStartable {
protected string _serviceName="monitor.base_service";
protected SiteConfigPacket _cfg;
protected IMessageQueue _mq;
private bool _Started = false;
private System.Timers.Timer _timer;
protected bool _Stopped=false;
private const int TIMER_INTRVAL=50;
public BaseService(string ServiceName,IMessageQueue mq,SiteConfigPacket cfg) {
_serviceName=ServiceName;
_mq=mq;
_cfg=cfg;
_timer=new System.Timers.Timer(TIMER_INTRVAL);
_timer.Elapsed+=new System.Timers.ElapsedEventHandler(timer_Elapsed);
}
public virtual string ServiceName {
get{return _serviceName;}
}
public virtual void Start() {
if(_Started==true) return;
DefaultLogger.INSTANCE.DEBUG(ServiceName+" Started");
_timer.Enabled=true;
_Started=true;
}
public virtual void Stop() {
_Stopped = true;
_timer.Enabled=false;
DefaultLogger.INSTANCE.DEBUG(ServiceName+" Stoped");
}
protected void ToNextRule(InfoData data,InfoConfig infocfg) {
string next=infocfg.getNextRule(_serviceName).Name;
if(next=="") next=ResultService.ServiceName;
this.addDataToQueue(next,data);
}
public virtual void handle(object data) {
}
protected void addDataToQueue(string sn,object data) {
_mq.addDataToQueue(sn,data);
}
protected void checkQueue() {
object obj=_mq.getDataFromQueue(_serviceName) ;
if(obj==null) return ;
try{
handle(obj);
}
catch(Exception e) {
DefaultLogger.INSTANCE.ERROR(this._serviceName+"("+obj.ToString()+")",e);
}
checkQueue();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
checkQueue();
}
}
}
这里使用了castle的自动服务启动功能,所以容器创建后,内部的所有服务都会自动启动,并且每隔50ms对它负责的队列进行一次集中的扫荡处理。如果是多个处理器实例,那么处理的效果更佳。那也很简单,在配置文件里类似如下配置:using System;
using System.Collections;
using OpenMonitor.Data;
using OpenMonitor.Utility;
using OpenMonitor;
using Castle.Model;
public class BaseService:IStartable {
protected string _serviceName="monitor.base_service";
protected SiteConfigPacket _cfg;
protected IMessageQueue _mq;
private bool _Started = false;
private System.Timers.Timer _timer;
protected bool _Stopped=false;
private const int TIMER_INTRVAL=50;
public BaseService(string ServiceName,IMessageQueue mq,SiteConfigPacket cfg) {
_serviceName=ServiceName;
_mq=mq;
_cfg=cfg;
_timer=new System.Timers.Timer(TIMER_INTRVAL);
_timer.Elapsed+=new System.Timers.ElapsedEventHandler(timer_Elapsed);
}
public virtual string ServiceName {
get{return _serviceName;}
}
public virtual void Start() {
if(_Started==true) return;
DefaultLogger.INSTANCE.DEBUG(ServiceName+" Started");
_timer.Enabled=true;
_Started=true;
}
public virtual void Stop() {
_Stopped = true;
_timer.Enabled=false;
DefaultLogger.INSTANCE.DEBUG(ServiceName+" Stoped");
}
protected void ToNextRule(InfoData data,InfoConfig infocfg) {
string next=infocfg.getNextRule(_serviceName).Name;
if(next=="") next=ResultService.ServiceName;
this.addDataToQueue(next,data);
}
public virtual void handle(object data) {
}
protected void addDataToQueue(string sn,object data) {
_mq.addDataToQueue(sn,data);
}
protected void checkQueue() {
object obj=_mq.getDataFromQueue(_serviceName) ;
if(obj==null) return ;
try{
handle(obj);
}
catch(Exception e) {
DefaultLogger.INSTANCE.ERROR(this._serviceName+"("+obj.ToString()+")",e);
}
checkQueue();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) {
checkQueue();
}
}
}
<component id="linearity"
type="OpenMonitor.Services.LinearityFormula,ExtendRule"
lifestyle="Pooled" initialPoolSize="2" maxPoolSize="5" >
</component>
但是实际上多个和一个处理效果没有区别,第二个总会扑空的,你看出来了吗?且听我下回分解吧。
alex 11-24