前言


本文主要是演示一个例子,服务器后台程序从PLC采集数据,并推送给在线客户端显示,以及推送给web端进行实时的显示,还支持远程操作,支持安卓端的同步监视和远程操作,关于HslCommunication的相关资料如下

nuget地址:https://www.nuget.org/packages/HslCommunication/            

github地址:https://github.com/dathlin/HslCommunication                                 如果喜欢可以star或是fork,还可以打赏支持。

在Visual Studio 中的NuGet管理器中可以下载安装,也可以直接在NuGet控制台输入下面的指令安装:

Install-Package HslCommunication

NuGet安装教程  http://www.cnblogs.com/dathlin/p/7705014.html

本项目的源代码地址:https://github.com/dathlin/RemoteMonitor

下面放几张截图:

服务器端的界面:

winform客户端地址:

web端的界面

所有的界面

安卓端

设计逻辑:

服务器端


主要是由数据订阅器,后台循环读取线程,在线管理器,同步网络交互网络组成。如下大致说一下各自负责的功能块:

数据订阅器

        /***************************************************************************************************************** *    本模块主要负责进行数据的发布。只要客户端订阅了相关的数据,服务器端进行推送后,客户端就可以收到数据*    *    因为本订阅器目前只支持字符串的数据订阅,所以在这里需要将byts[]转化成base64编码的数据,相关的知识请自行百度,此处不再说明* *****************************************************************************************************************/private NetPushServer pushServer = null;                 // 订阅发布核心服务器private void NetPushServerInitialization( ){pushServer = new NetPushServer( );pushServer.LogNet = LogNet;pushServer.ServerStart( 23467 );}

当你想要推送数据的时候,按照下面的方法

pushServer.PushString( "A", "这是测试数据");    // 推送数据,关键字为A

推送的测试数据到时候换成实际的数据即可。

后台循环读取数据

        /**************************************************************************************************************** *    以下演示了西门子的读取类,对于三菱和欧姆龙,或是modbustcp来说,逻辑都是一样的,你也可以尝试着换成三菱的类,来加深理解* *****************************************************************************************************************/private SiemensS7Net siemensTcpNet;                                                // 西门子的网络访问器private bool isReadingPlc = false;                                                 // 是否启动的标志,可以用来暂停项目private int failed = 0;                                                            // 连续失败此处,连续三次失败就报警private Thread threadReadPlc = null;                                               // 后台读取PLC的线程private void SiemensTcpNetInitialization( ){siemensTcpNet = new SiemensS7Net( SiemensPLCS.S1200 );                          // 实例化西门子的对象siemensTcpNet.IpAddress = "192.168.1.195";                                     // 设置IP地址siemensTcpNet.LogNet = LogNet;                                                 // 设置统一的日志记录器siemensTcpNet.ConnectTimeOut = 1000;                                           // 超时时间为1秒// 启动后台读取的线程threadReadPlc = new Thread( new System.Threading.ThreadStart( ThreadBackgroundReadPlc ) );threadReadPlc.IsBackground = true;threadReadPlc.Priority = ThreadPriority.AboveNormal;threadReadPlc.Start( );}private Random random = new Random( );private bool isReadRandom = false;private void ThreadBackgroundReadPlc( ){// 此处假设我们读取的是西门子PLC的数据,其实三菱的数据读取原理是一样的,可以仿照西门子的开发/*************************************************************************************************** *    假设一:M100,M101存储了一个温度值,举例,100.5℃数据为1005*    假设二:M102存储了设备启停信号,0为停止,1为启动*    假设三:M103-M106存储了一个产量值,举例:12345678* **************************************************************************************************/while (true){if (isReadingPlc){// 这里仅仅演示了西门子的数据读取// 事实上你也可以改成三菱的,无非解析数据的方式不一致而已,其他数据推送代码都是一样的HslCommunication.OperateResult<JObject> read = null; //siemensTcpNet.Read( "M100", 7 );if (isReadRandom){// 当没有测试的设备的时候,此处就演示读取随机数的情况read = HslCommunication.OperateResult.CreateSuccessResult( new JObject( ){{"temp",new JValue(random.Next(2000)/10d) },{"enable",new JValue(random.Next(100)>10) },{"product",new JValue(random.Next(10000)) }} );}else{HslCommunication.OperateResult<byte[]> tmp = siemensTcpNet.Read( "M100", 7 );if(tmp.IsSuccess){double temp1 = siemensTcpNet.ByteTransform.TransInt16( tmp.Content, 0 ) / 10.0;bool machineEnable = tmp.Content[2] != 0x00;int product = siemensTcpNet.ByteTransform.TransInt32( tmp.Content, 3 );read = HslCommunication.OperateResult.CreateSuccessResult( new JObject( ){{"temp",new JValue(temp1) },{"enable",new JValue(machineEnable) },{"product",new JValue(product) }} );}else{read = HslCommunication.OperateResult.CreateFailedResult<JObject>( tmp );}}if (read.IsSuccess){failed = 0;                                                              // 读取失败次数清空pushServer.PushString( "A", read.Content.ToString() );    // 推送数据,关键字为AShowReadContent( read.Content );                                         // 在主界面进行显示,此处仅仅是测试,实际项目中不建议在服务端显示数据信息}else{failed++;ShowFailedMessage( failed );                             // 显示出来读取失败的情况}}Thread.Sleep( 500 );                            // 两次读取的时间间隔}}// 只是用来显示连接失败的错误信息private void ShowFailedMessage(int failed){if(InvokeRequired){Invoke(new Action<int>(ShowFailedMessage), failed);return;}textBox1.AppendText(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff ") + "第" + failed + "次读取失败!" + Environment.NewLine);}// 读取成功时,显示结果数据private void ShowReadContent(JObject content){// 本方法是考虑了后台线程调用的情况if(InvokeRequired){// 如果是后台调用显示UI,那么就使用委托来切换到前台显示Invoke(new Action<JObject>(ShowReadContent), content);return;}// 提取数据double temp1 = content["temp"].ToObject<double>( );bool machineEnable = content["enable"].ToObject<bool>( );int product = content["product"].ToObject<int>( );// 实际项目的时候应该在此处进行将数据存储到数据库,你可以选择MySql,SQL SERVER,ORACLE等等// SaveDataSqlServer( temp1 );         // 此处演示写入了SQL 数据库的方式// 开始显示label2.Text = temp1.ToString();label2.BackColor = temp1 > 100d ? Color.Tomato : Color.Transparent;  // 如果温度超100℃就把背景改为红色label3.Text = product.ToString();// 添加到缓存数据AddDataHistory( (float)temp1 );label5.Text = machineEnable ? "运行中" : "未启动";}

这里面包含了后台的循环读取并且显示的操作,还支持了在没有实际的设备的情况下,直接用模拟数据来测试的情况。

这里为什么直接使用json对象来传送呢,是为了包装成一个统一的模型对象,方便后续的客户端直接进行提取操作。

在线客户端管理模块

这部分的功能需要根据实际情况来确认,如果不需要,可以直接删除,这部分的功能主要是实现在服务器端对所有在线的winform程序的在线情况进行掌控,并可以在客户端刚上线的时候处理一些事情。

        /****************************************************************************************************** *    特别说明:在线网络的模块的代码主要是为了支持服务器对客户端在线的情况进行管理*    *             当客户端刚上线的时候,服务器也可以发送一些初始数据给客户端* *****************************************************************************************************/private NetComplexServer netComplex;                            // 在线网络管理核心private void NetComplexInitialization( ){netComplex = new NetComplexServer( );                        // 实例化netComplex.AcceptString += NetComplex_AcceptString;          // 绑定字符串接收事件netComplex.ClientOnline += NetComplex_ClientOnline;          // 客户端上线的时候触发netComplex.ClientOffline += NetComplex_ClientOffline;        // 客户端下线的时候触发netComplex.LogNet = LogNet;                                  // 设置日志netComplex.ServerStart( 23456 );                             // 启动网络服务}private void NetComplex_ClientOffline( AppSession session, string object2 ){// 客户端下线的时候触发方法RemoveOnLine( session.ClientUniqueID );}private void NetComplex_ClientOnline( AppSession session ){// 回发一条初始化数据的信息netComplex.Send( session, 2, GetHistory( ) );// 有客户端上限时触发方法NetAccount account = new NetAccount( ){Guid = session.ClientUniqueID,Ip = session.IpAddress,Name = session.LoginAlias,OnlineTime = DateTime.Now,};AddOnLine( account );}private void NetComplex_AcceptString( AppSession stateone, HslCommunication.NetHandle handle, string data ){// 接收到客户端发来的数据时触发}

  

本例子里还包含了在线的客户端账号信息,支持扩展额外的信息登录

private List<NetAccount> all_accounts = new List<NetAccount>( );private object obj_lock = new object( );// 新增一个用户账户到在线客户端private void AddOnLine( NetAccount item ){lock (obj_lock){all_accounts.Add( item );}UpdateOnlineClients( );}// 移除在线账户并返回相应的在线信息private void RemoveOnLine( string guid ){lock (obj_lock){for (int i = 0; i < all_accounts.Count; i++){if (all_accounts[i].Guid == guid){all_accounts.RemoveAt( i );break;}}}UpdateOnlineClients( );}/// <summary>/// 更新客户端在线信息/// </summary>private void UpdateOnlineClients( ){if (InvokeRequired && IsHandleCreated){Invoke( new Action( UpdateOnlineClients ) );return;}lock (obj_lock){listBox1.DataSource = all_accounts.ToArray( );}

账号的类为

    /// <summary>/// 用于在线控制的网络类/// </summary>public class NetAccount{/// <summary>/// 唯一ID/// </summary>public string Guid { get; set; }/// <summary>/// Ip地址/// </summary>public string Ip { get; set; }/// <summary>/// 上线时间/// </summary>public DateTime OnlineTime { get; set; }/// <summary>/// 名称/// </summary>public string Name { get; set; }private string GetOnlineTime(){TimeSpan ts = DateTime.Now - OnlineTime;if (ts.TotalSeconds < 60){return ts.Seconds + " 秒";}else if(ts.TotalHours < 1){return ts.Minutes + "分" + ts.Seconds + "秒";}else if(ts.TotalDays < 1){return ts.Hours + "时" + ts.Minutes + "分";}else{return ts.Days + "天" + ts.Hours + "时";}}/// <summary>/// 字符串标识形式/// </summary>/// <returns></returns>public override string ToString( ){return "[" + Ip + "] : 在线时间 " + GetOnlineTime( );}}

  

同步的网络模块

这部分的功能相当于一个接口功能,为了支持远程的客户端或是web端进行对PLC进行读写操作实现的,事实上,当远程的程序点击了启动XX功能之后,远程的代码就通过同步网络将消息都发送给了服务器,服务器再去操作PLC,然后在回发给远程结果。

        /****************************************************************************************************** *    特别说明:同步网络模块,用来支持远程的写入操作,特点是支持是否成功的反馈,这个信号对客户端来说是至关重要的*    *             不仅仅支持客户端的操作,还支持web端的操作。* *****************************************************************************************************/private NetSimplifyServer netSimplify;                                     // 同步网络访问的服务支持private void NetSimplifyInitialization( ){netSimplify = new NetSimplifyServer( );                                // 实例化netSimplify.ReceiveStringEvent += NetSimplify_ReceiveStringEvent;      // 服务器接收字符串信息的时候,触发netSimplify.LogNet = LogNet;                                           // 设置日志netSimplify.ServerStart( 23457 );                                      // 启动服务}private void NetSimplify_ReceiveStringEvent( AppSession session, HslCommunication.NetHandle handle, string msg ){if (handle == 1){string tmp = StartPLC( );LogNet?.WriteInfo( tmp );// 远程启动设备netSimplify.SendMessage( session, handle, tmp );}else if (handle == 2){string tmp = StopPLC( );LogNet?.WriteInfo( tmp );// 远程停止设备netSimplify.SendMessage( session, handle, tmp );}else{netSimplify.SendMessage( session, handle, msg );}}

  

客户端实现,

web端的数据推送实现,需要SignalR支持,关于这方面的技术细节,可以参考SignalR官网:https://www.asp.net/signalr

本项目还支持了简单的图表显示,图标的支持来源于百度的echart项目,http://echarts.baidu.com/

安卓客户端,主要是订阅器的实现和同步客户端的实现

转载于:https://www.cnblogs.com/dathlin/p/9129070.html

使用HslCommunication实现PLC数据的远程客户端监视,以及web端实时监视,远程操作设备示例...相关推荐

  1. 手机web端唤醒qq客户端以及电脑web端唤醒qq客户端

    1 电脑网页唤醒qq客户端 http://shang.qq.com/v3/widget.html 先在qq推广申请下,几分钟就弄好了,不然会有提示 <a target="_blank& ...

  2. plc tcp ip通讯怎么只能连一个客户端_如何远程读取西门子PLC数据?

    随着工业的发展,PLC联网进行远程监控.远程运维的需求越来越多,通常是通过PLC的通信口外接一个联网模块来实现.很多企业自动化产品与非标自动化产品安装现场地处偏僻,没有网络怎么办?随着本地通信控制的局 ...

  3. java 远程udp_远程客户端不接收UDP数据包

    我有简单的UDP服务器/客户端程序,我转发我的端口和服务器通过互联网接收和发送数据包,但远程机器上的客户端无法接收它们,所以我想知道如何在客户端没有转发端口的情况下接收数据包(如果它甚至可能)?如果它 ...

  4. 无线远程模块的应用,手机APP远程监控PLC数据技术方案

    无线远程模块的应用,手机APP远程监控PLC数据技术方案 (巨控何工_原创) 无线远程模块用途:广泛,遍及智能交通.环境保护.政府工作.公共安全.智能消防.工业监测.环境监测.路灯照明管控.景观照明管 ...

  5. PLC数据通过无线远程传输到电脑上。也支持力控组态王远程读取,也支持云组态

    PLC远程监控 概述:随着移动互联网的普及,越来越多的用户希望通过智能手机远程监控现场的PLC数据,这样PLC就可以实现在异地监控了. 一.远程PLC监控系统的原理  二. 远程监控PLC的硬件要求 ...

  6. s7 200 java_java android 读写西门子PLC数据,包含S7协议和Fetch/Write协议,s7支持200smart,300PLC,1200PLC,1500PLC...

    本文将使用一个gitHub开源的组件技术来读写西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 gi ...

  7. C#读写三菱PLC数据 使用TCP/IP 协议

    本文将使用一个Github开源的组件库技术来读写三菱PLC和西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能 ...

  8. python三菱_python 读写三菱PLC数据,使用以太网读写Q系列,L系列,Fx系列的PLC数据...

    本文将使用一个gitHub开源的组件技术来读写三菱的plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能读写操作 里面 ...

  9. C#读写三菱PLC和西门子PLC数据 使用TCP/IP 协议

    本文将使用一个Github开源的组件库技术来读写三菱PLC和西门子plc数据,使用的是基于以太网的TCP/IP实现,不需要额外的组件,读取操作只要放到后台线程就不会卡死线程,本组件支持超级方便的高性能 ...

最新文章

  1. 提供一个基于.NET的加密/解密算法
  2. C# 关键字Event
  3. YII2 载入默认值 loadDefaultValues
  4. 马斯克的SpaceX又双叒叕融资了:喜提131亿,估值破3000亿
  5. python对财务人员的帮助-帮公司财务妹子写了个“群发工资条”的Python脚本!
  6. SpringCloud源码分析(一)--客户端搭建
  7. java实现遍历文件夹下的文件及文件夹
  8. 微信小程token_微信小程序开发之登录换取token
  9. 【hortonworks/registry】AVRO 规范-Schema的定义和声明
  10. vue----sourceMap
  11. EXCEL数据有效性—单元格筛选的改进
  12. 树形DP-HDU1561 The more, The Better
  13. 8.2 GOF设计模式一: 单实例模式 SingleTon
  14. stvd使用c语言编程,STVD使用教程.pdf
  15. pg PostGIS教程:几何图形(geometry)
  16. cleanmymac是怎么进行Mac的深度清理的
  17. eclipse安装wtp
  18. 阿里云短信申请流程以及配置
  19. 【矩阵论】1.准备知识——复数域上的内积域正交阵
  20. 说说 java包与导包

热门文章

  1. 工作中学习,学习中成长
  2. 整理vim格式回车变成空两格
  3. 单片机和微型计算机异同,微机与单片机有什么主要的区别?
  4. ahjesus自定义隐式转换和显示转换
  5. 机器学习面试(作者面了8家公司,它们问了如下题目......)
  6. python xlrd模块_Python中xlrd模块解析
  7. 如何从asio::udp::socket()中取出底层sockfd整数
  8. C# WPD PortableDeviceApiLib获取便携设备列表
  9. SpringBoot+Nacos+Seata实现Dubbo分布式事务管理
  10. 【java学习之路】(java框架)003.Mybatis的介绍和基本使用