监控系统应用比较广泛,监控对象也是包罗万象,以下就拿监控注塑机器来说,机器的主要参数如开模、合模、熔胶、射胶、冷却、松退、顶出等运行参数需要实时监控,监控的机器不止一台,是很多台,监控到的数据了要提交到存储系统保存起来;
1、如何监控机器的在线与离线状态
实现方法:创建一个后台线程,线程内一个while循环,循环内异步Ping,Ping完成事件内确定机器的在线状态;
//创建ping线程
_pingThread = new Thread(PingMachines, 1024 * 30);
_pingThread.IsBackground = true;
_pingThread.Start();
///
/// ping所有的机器 变量_PingThreadStop在关闭程序时为True
///
private void PingMachines()
{
string machinename, ip,tmpstr;
try
{
while (!_PingThreadStop)
{
if (_PingCount > 0) { continue; }
lock (olock) ;
//机器列表
foreach (DataRow dr in opcdata.tbMachines.Rows)
{
//获取要ping的机器及IP
machinename = dr["MachineName"].ToString();
ip = dr["MachineIP"].ToString();
dr["MachineOnline"] = _OnlineMachine.TryGetValue(machinename, out tmpstr);
//ping计数器,避免产生太多ping
Interlocked.Increment(ref _PingCount);
//ping方法
toolhelper.PingIP(machinename, ip,PingCompletedEvent);
Thread.Sleep(1000);
}
Thread.Sleep(2000);
}
}
catch (Exception ex)
{
log4.Error("error", ex);
}
}
///
/// ping 完成事件
///
///
///
public void PingCompletedEvent(object sender, PingCompletedEventArgs e)
{
string machinename = "";
string ip = "";
string tmpstr = "";
bool findflag;
try
{
//ping计数器减1
Interlocked.Decrement(ref _PingCount);
//获取ping用户自定义数据
if (e.UserState is pingSendData)
{
machinename = ((pingSendData)e.UserState).machineNo;
ip = ((pingSendData)e.UserState).clientIP;
}
//ping 结果
bool pingRes = e.Reply.Status == IPStatus.Success;
//获取在线机器
findflag = _OnlineMachine.TryGetValue(machinename, out tmpstr);
//离线切换到在线
if (pingRes && !findflag)
{
_OnlineMachine.TryAdd(machinename, machinename);
OPCObj.AddMachineAlarm(machinename);
}
else
{
//在线切换到离线
if (!pingRes && findflag)
{
_OnlineMachine.TryRemove(machinename, out tmpstr);
}
}
}
catch (Exception ex)
{
log4.Error("error", ex);
}
finally {
//释放ping对象
if (sender is Ping)
{
(sender as Ping).Dispose();
}
}
}
///
/// 判断IP是否通
///
///
///
///
public void PingIP(string machineNo,string ip, PingCompletedEventHandler PingCompletedEvent)
{
Ping ping = new Ping();
ping.PingCompleted += PingCompletedEvent;
ping.SendAsync(ip,2000, new pingSendData { machineNo = machineNo, clientIP = ip });
}
2、如何将获取到数据异步提交到API接口
实现方法:创建post对象,准备好post数据,异步上传数据,上传完成事件处理结果;
///
/// 数据提交主方法
///
///
public void SubmitData(string Machine, int ProductQT,string Createtime, out bool success, out string errmsg, UploadDataCompletedEventHandler UploadDataCompletedEvent)
{
success = true;
errmsg = "";
DataRow[] drs;
OPCTool opctool = new OPCTool();
//重新获取当前最新参数数据
drs = RunDataTable.Select(自已的查询条件));
if (drs == null || drs.Length == 0) { success = false; return; }
WebException webexec;
try
{
using (DataTable tmpTable1 = drs.CopyToDataTable()) {
Dictionary inputs = new Dictionary();
inputs.Add("machine", Machine);
inputs.Add("ip", MachineIPDict.ContainsKey(Machine));
inputs.Add("paraslist", tmpTable1);
inputs.Add("currtime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
inputs.Add("modeluenum", ProductQT);
inputs.Add("url", API_Url);
//自定义数据
Dictionary userToken = new Dictionary();
userToken.Add("title", "RUNDATA");
userToken.Add("url", API_Url);
userToken.Add("machine", inputs["machine"].ToString());
opctool.HttpPost(inputs["url"].ToString(), JsonConvert.SerializeObject(inputs), UploadDataCompletedEvent,out webexec, "", userToken);
if (webexec != null) {
success = false;
errmsg = webexec.StackTrace;
}
inputs = null;
}
}
finally
{
opctool = null;
drs = null;
}
}
///
/// 异步POST
///
///
/// 上传数据
/// 上传完成事件
///
/// 调用异常
/// 用户自定义数据
public void HttpPost(string url, string postData, UploadDataCompletedEventHandler UploadDataCompleted, out WebException ex,string ContentType = "application/json",object userToken=null) {
using (var client = new WebClient())
{
client.UploadDataCompleted += UploadDataCompleted;
try
{
client.Headers.Add("Content-Type", ContentType==""? "application/json": ContentType);
byte[] poststream = Encoding.UTF8.GetBytes(postData);
client.UploadDataAsync(new Uri(url),"POST", poststream,userToken);
ex = null;
}
catch (WebException exce)
{
ex = exce;
}
}
}
///
/// 上传数据完成事件处理
///
///
///
public void UploadDataCompletedEvent(object sender, UploadDataCompletedEventArgs e)
{
StringBuilder sb = new StringBuilder();
Dictionary userToken = new Dictionary();
if (e.Error == null)
{
//获取api返回数据
string resultstr = Encoding.UTF8.GetString(e.Result);
//转换为json对象
JObject result = (JObject)JsonConvert.DeserializeObject(resultstr);
if (e.UserState != null && (e.UserState is Dictionary)) {
userToken = (e.UserState as Dictionary);
}
if (!(bool)result["success"])
{
outputmsg(result["resmsg"].ToString());
}
else
{
if (userToken.ContainsKey("title")) {
sb.Append(userToken["title"]);
}
if (userToken.ContainsKey("machine"))
{
sb.Append(" 机器:"+userToken["machine"]);
}
if (userToken.ContainsKey("url"))
{
sb.Append(" 提交网址:" + userToken["url"]);
}
outputmsg(sb.ToString() + "成功 ");
sb = null;
userToken = null;
}
}
else {
if (userToken.ContainsKey("title"))
{
sb.Append(userToken["title"]);
}
if (userToken.ContainsKey("machine"))
{
sb.Append(" 机器:" + userToken["machine"]);
}
if (userToken.ContainsKey("url"))
{
sb.Append(" 提交网址:" + userToken["url"]);
}
sb.Append(" 失败,错误:"+e.Error.StackTrace);
outputmsg(sb.ToString());
sb = null;
userToken = null;
}
}
异步的好处就是动作不会对线程造成阻塞,不会造成CPU利率居高不下,如果一开始用的是同步,改为异步后,CPU利用率会马上降下来并保持小范围的波动;