基于C#打造的OPCUA客户端应用
OPC UA (Unified Architecture),是工业4.0的标准通信规范,大家现在都不陌生。
目前大部分工控行业的应用系统都逐渐的在向OPC UA靠拢,所以随着iot的发展,OPC UA势必会有更加广阔的应用前景,
所以我们应该投入研发力量来研究OPC UA的相关技术规范,并开始应用到业务系统。
基于此行业形势,为了满足公司的需要,用C#打造了一套OPC UA客户端封装组件,与大家共勉。
组件源码参见下面代码,先简单罗列下OPC UA的相关技术的核心概念,加深大家对OPC UA的理解。
OPC UA是什么?
OPC通信标准的核心是互通性 (Interoperability) 和标准化 (Standardization) 问题。传统的OPC技术在控制级别很好地 解决了硬件设备间的互通性问题, 在企业层面的通信标准化是同样需要的。OPC UA之前的访问规范都是基于微软的COM/DCOM技术, 这会给新增层面的通信带来不可根除的弱点。加上传统OPC技术不够灵活、平台局限等问题的逐渐凸显, OPC基金会 (OPC Foundation) 发布了最新的数据通讯统一方法 — OPC统一架构 (OPC UA), 涵盖了OPC 实时数据访问规范 (OPC DA)、OPC历史数据访问规范 (OPC HDA)、 OPC 报警事件访问规范 (OPC A&E) 和OPC安全协议 (OPC Security) 的不同方面, 但在其基础之上进行了功能扩展。
OPC UA,是在传统OPC技术取得很大成功之后的又一个突破,让数据采集、信息模型化以及工厂底层与企业层面之间的通讯更加安全、可靠。
OPC UA的几大优势:
1、与平台无关,可在任何操作系统上运行
2、为未来的先进系统做好准备,与保留系统继续兼容
3、配置和维护更加方便
4、基于服务的技术
5、可见性增加
6、通信范围更广
7、通信性能提高
OPC UA的主要特点:
1、访问统一性
OPC UA有效地将现有的OPC规范 (DA、A&E、HDA、命令、复杂数据和对象类型) 集成进来,成为现在的新的OPC UA规范。 OPC UA提供了一致、完整的地址空间和服务模型,解决了过去同一系统的信息不能以统一方式被访问的问题。
2、通信性能
OPC UA 规范可以通过任何单一端口 (经管理员开放后)进行通信。这让穿越防火墙不再是OPC通信的路障,并且为提高传输性能, OPC UA消息的编码格式可以是XML文本格式或二进制格式,也可使用多种传输协议进行传输,比如:TCP和通过HTTP的网络服务。
3、可靠性、冗余性
OPC UA的开发含有高度可靠性和冗余性的设计。可调试的逾时设置,错误发现和自动纠正等新特征, 都使得符合OPC UA规范的软件产品可以很自如地处理通信错误和失败。 OPC UA的标准冗余模型也使得来自不同厂商的软件应用可以同时被采纳并彼此兼容。
4、标准安全模型
OPC UA 访问规范明确提出了标准安全模型, 每个OPC UA应用都必须执行OPC UA安全协议, 这在提高互通性的同时降低了维护和额外配置费用。 用于OPC UA应用程序之间传递消息的底层通信技术提供了加密功能和标记技术, 保证了消息的完整性,也防止信息的泄漏。
5、平台无关
OPC UA软件的开发不再依靠和局限于任何特定的操作平台。过去只局限于Windows平台的OPC技术拓展到了Linux、Unix、Mac等各种其它平台。 基于Internet的WebService服务架构 (SOA) 和非常灵活的数据交换系统, OPC UA的发展不仅立足于现在,更加面向未来。
下面给大家分享一下项目中用到的应用组件(完全干货),核心源代码(部分)如下:(组件应用交流QQ群:706224870,群文件里有完整的组件源代码及测试DEMO,供大家参考)
其他相关应用请参考:https://blog.csdn.net/mql007007
主要有两个核心类OpcUaClientAPI和PLCMgt。
OpcUaClientAPI:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using Opc.Ua;
using Opc.Ua.Client;
namespace OpcUaClientAPI
{
public class OpcUaClientAPI
{
#region Construction
public OpcUaClientAPI()
{
// Creats the application configuration (containing the certificate) on construction
mApplicationConfig = CreateClientConfiguration("demo", "LocalMachine\\My", "localhost");
}
public OpcUaClientAPI(string applicationName, string storePath, string storeIP)
{
// Creats the application configuration (containing the certificate) on construction
mApplicationConfig = CreateClientConfiguration(applicationName, storePath, storeIP);
}
#endregion
#region Properties
/// <summary>
/// Keeps a session with an UA server.
/// </summary>
private Session mSession = null;
/// <summary>
/// Specifies this application
/// </summary>
private ApplicationConfiguration mApplicationConfig = null;
/// <summary>
/// Provides the session being established with an OPC UA server.
/// </summary>
public Session Session
{
get { return mSession; }
}
/// <summary>
/// Provides the event for value changes of a monitored item.
/// </summary>
public MonitoredItemNotificationEventHandler ItemChangedNotification = null;
/// <summary>
/// Provides the event for KeepAliveNotifications.
/// </summary>
public KeepAliveEventHandler KeepAliveNotification = null;
#endregion
#region Discovery
/// <summary>Finds Servers based on a discovery url</summary>
/// <param name="discoveryUrl">The discovery url</param>
/// <returns>ApplicationDescriptionCollection containing found servers</returns>
/// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
public ApplicationDescriptionCollection FindServers(string discoveryUrl)
{
//Create a URI using the discovery URL
Uri uri = new Uri(discoveryUrl);
try
{
//Ceate a DiscoveryClient
DiscoveryClient client = DiscoveryClient.Create(uri);
//Find servers
ApplicationDescriptionCollection servers = client.FindServers(null);
return servers;
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
/// <summary>Finds Endpoints based on a server's url</summary>
/// <param name="discoveryUrl">The server's url</param>
/// <returns>EndpointDescriptionCollection containing found Endpoints</returns>
/// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
public EndpointDescriptionCollection GetEndpoints(string serverUrl)
{
//Create a URI using the server's URL
Uri uri = new Uri(serverUrl);
try
{
//Create a DiscoveryClient
DiscoveryClient client = DiscoveryClient.Create(uri);
//Search for available endpoints
EndpointDescriptionCollection endpoints = client.GetEndpoints(null);
return endpoints;
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
#endregion
#region Connect/Disconnect
/// <summary>
/// 连接
/// </summary>
/// <param name="url"></param>
/// <param name="security"></param>
/// <param name="userIdentity"></param>
public void Connect(string url, bool security, UserIdentity userIdentity)
{
try
{
//Secify application configuration
ApplicationConfiguration ApplicationConfig = mApplicationConfig;
//Hook up a validator function for a CertificateValidation event
mApplicationConfig.CertificateValidator.CertificateValidation += Validator_CertificateValidation;
//Create EndPoint description
EndpointDescription EndpointDescription = CreateEndpointDescription(url, security);
//Create EndPoint configuration
EndpointConfiguration EndpointConfiguration = EndpointConfiguration.Create(ApplicationConfig);
//Create an Endpoint object to connect to server
ConfiguredEndpoint Endpoint = new ConfiguredEndpoint(null, EndpointDescription, EndpointConfiguration);
//Create anonymous user identity
//UserIdentity UserIdentity = new UserIdentity();
//Create and connect session
mSession = Session.Create(
ApplicationConfig,
Endpoint,
true,
"MySession",
60000,
userIdentity,
null
);
mSession.KeepAlive += new KeepAliveEventHandler(Notification_KeepAlive);
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
/// <summary>
/// 连接
/// </summary>
/// <param name="endpointDescription"></param>
/// <param name="userIdentity"></param>
public void Connect(EndpointDescription endpointDescription, UserIdentity userIdentity)
{
try
{
//Secify application configuration
ApplicationConfiguration ApplicationConfig = mApplicationConfig;
//ApplicationConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates = true;
//Hook up a validator function for a CertificateValidation event
ApplicationConfig.CertificateValidator.CertificateValidation += Validator_CertificateValidation;
//Create EndPoint configuration
EndpointConfiguration EndpointConfiguration = EndpointConfiguration.Create(ApplicationConfig);
//Connect to server and get endpoints
ConfiguredEndpoint mEndpoint = new ConfiguredEndpoint(null, endpointDescription, EndpointConfiguration);
//Create the binding factory.
BindingFactory bindingFactory = BindingFactory.Create(mApplicationConfig, ServiceMessageContext.GlobalContext);
//Create anonymous user identity
//UserIdentity UserIdentity = new UserIdentity();
//Create and connect session
mSession = Session.Create(
ApplicationConfig,
mEndpoint,
true,
"MySession",
60000,
userIdentity,
null
);
mSession.KeepAlive += new KeepAliveEventHandler(Notification_KeepAlive);
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
/// <summary>
/// 增加PLC会话超时时间
/// </summary>
/// <param name="url"></param>
/// <param name="security"></param>
/// <param name="userIdentity"></param>
/// <param name="timeOverMinutes">会话超时分钟数,单位分钟</param>
public void Connect(string url, bool security, UserIdentity userIdentity, int timeOverMinutes)
{
try
{
//Secify application configuration
ApplicationConfiguration ApplicationConfig = mApplicationConfig;
//Hook up a validator function for a CertificateValidation event
mApplicationConfig.CertificateValidator.CertificateValidation += Validator_CertificateValidation;
//Create EndPoint description
EndpointDescription EndpointDescription = CreateEndpointDescription(url, security);
//Create EndPoint configuration
EndpointConfiguration EndpointConfiguration = EndpointConfiguration.Create(ApplicationConfig);
//Create an Endpoint object to connect to server
ConfiguredEndpoint Endpoint = new ConfiguredEndpoint(null, EndpointDescription, EndpointConfiguration);
//Create anonymous user identity
//UserIdentity UserIdentity = new UserIdentity();
//Create and connect session
mSession = Session.Create(
ApplicationConfig,
Endpoint,
true,
"MySession",
Convert.ToUInt32(timeOverMinutes * 60000),
userIdentity,
null
);
mSession.KeepAlive += new KeepAliveEventHandler(Notification_KeepAlive);
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
/// <summary>
/// 增加PLC会话超时时间
/// </summary>
/// <param name="endpointDescription"></param>
/// <param name="userIdentity"></param>
/// <param name="timeOverMinutes"></param>
public void Connect(EndpointDescription endpointDescription, UserIdentity userIdentity, int timeOverMinutes)
{
try
{
//Secify application configuration
ApplicationConfiguration ApplicationConfig = mApplicationConfig;
//ApplicationConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates = true;
//Hook up a validator function for a CertificateValidation event
ApplicationConfig.CertificateValidator.CertificateValidation += Validator_CertificateValidation;
//Create EndPoint configuration
EndpointConfiguration EndpointConfiguration = EndpointConfiguration.Create(ApplicationConfig);
//Connect to server and get endpoints
ConfiguredEndpoint mEndpoint = new ConfiguredEndpoint(null, endpointDescription, EndpointConfiguration);
//Create the binding factory.
BindingFactory bindingFactory = BindingFactory.Create(mApplicationConfig, ServiceMessageContext.GlobalContext);
//Create anonymous user identity
//UserIdentity UserIdentity = new UserIdentity();
//Create and connect session
mSession = Session.Create(
ApplicationConfig,
mEndpoint,
true,
"MySession",
Convert.ToUInt32(timeOverMinutes * 60000),
userIdentity,
null
);
mSession.KeepAlive += new KeepAliveEventHandler(Notification_KeepAlive);
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
/// <summary>Closes an existing session and disconnects from the server.</summary>
/// <exception cref="Exception">Throws and forwards any exception with short error description.</exception>
public void Disconnect()
{
// Close the session.
try
{
mSession.Close(10000);
mSession.Dispose();
}
catch (Exception e)
{
//handle Exception here
throw e;
}
}
#endregion
PLCMgt:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Collections;
using System.Threading;
using Opc.Ua;
using Opc.Ua.Client;
using BaseAPI;
using Common;
using OpcUaClientAPI;
namespace PLC_OPCUA_Mgt
{
public class PLCMgt
{
#region 定义
ConfigParams configParams = null;
OpcUaClientAPI.OpcUaClientAPI opcuaClientAPI = null;
Session PLCSession = null;
public Queue PLCBaseState = new Queue(); //PLC基本状态队列
private string last_PLCBaseState = string.Empty; //上次订阅值
List<SubscribeQueue> _subscribeQueues = new List<SubscribeQueue>();
/// <summary>
/// 订阅监控项结果字典,不同的监控项存入不同的队列
/// </summary>
private List<SubscribeQueue> SubscribeQueues
{
get
{
return this._subscribeQueues;
}
set
{
this._subscribeQueues = value;
}
}
private bool UseOPCUA = false; //OPCUA通道是否可用
#endregion
public PLCMgt(ConfigParams configParamsP)
{
this.configParams = configParamsP;
opcuaClientAPI = new OpcUaClientAPI.OpcUaClientAPI(this.configParams.ApplicationName, this.configParams.StorePath, this.configParams.StoreIP);
//启动连接
Session tmpSession = this.ConnectPLC();
/处理OPCUA通信连接状态
if (tmpSession.Connected)
{
this.UseOPCUA = true;
ThreadStart AutoOPCUA = new ThreadStart(MonitorOPCUAConnection);
Thread AutoOPCUAThread = new Thread(AutoOPCUA);
AutoOPCUAThread.Start();
}
}
/// <summary>
/// 连接PLC
/// </summary>
/// <returns></returns>
public Session ConnectPLC()
{
UserIdentity UserIdentity = new UserIdentity(this.configParams.PLCConnectedUser, this.configParams.PLCConnectedPwd);
EndpointDescription tmpEndpointDesc = null;
try
{
ApplicationDescriptionCollection servers = this.opcuaClientAPI.FindServers(this.configParams.PLCAddr);
foreach (ApplicationDescription ad in servers)
{
foreach (string url in ad.DiscoveryUrls)
{
EndpointDescriptionCollection endpoints = this.opcuaClientAPI.GetEndpoints(url);
foreach (EndpointDescription ep in endpoints)
{
tmpEndpointDesc = ep;
break;
}
}
}
for (int i = 0; i < int.Parse(this.configParams.ReStartMaxCnt); i++)
{
//增加PLC会话超时时间到10分钟
//this.opcuaClientAPI.Connect(tmpEndpointDesc, UserIdentity);
this.opcuaClientAPI.Connect(tmpEndpointDesc, UserIdentity, 10);
this.PLCSession = this.opcuaClientAPI.Session;
if (this.PLCSession != null && !this.PLCSession.Disposed)
{
this.opcuaClientAPI.KeepAliveNotification += new KeepAliveEventHandler(Notification_KeepAlive);
}
if (i == 4 && this.PLCSession == null)
{
string logcontent = DateTime.Now.ToString() + " 连接PLC失败!原因:超过最大连接次数(" + this.configParams.ReStartMaxCnt + ")。";
BaseApiHandler.RecordLog(logcontent, this.configParams.Logpath, "ConnecPLC", this.configParams.RecordBizDataLog);
}
if (this.PLCSession.Connected)
{
string logcontent = DateTime.Now.ToString() + " 连接PLC成功!";
BaseApiHandler.RecordLog(logcontent, this.configParams.Logpath, "连接PLC成功", this.configParams.RecordBizDataLog);
break; //连上就终止再连
}
}
}
catch (Exception ex)
{
string logcontent = DateTime.Now.ToString() + " 连接PLC发生异常。原因:" + ex.Message;
BaseApiHandler.RecordLog(logcontent, this.configParams.Logpath, "ConnecPLC", this.configParams.RecordBizDataLog);
}
return this.PLCSession;
}
/// <summary>
/// 处理保持连接
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public void Notification_KeepAlive(Session sender, KeepAliveEventArgs e)
{
//Handle KeepAlive here
}
/// <summary>
/// 监控OPCUA通信连接
/// </summary>
private void MonitorOPCUAConnection()
{
while (true)
{
try
{
if (!this.UseOPCUA)
{
this.opcuaClientAPI = null;
this.opcuaClientAPI = new OpcUaClientAPI.OpcUaClientAPI(this.configParams.ApplicationName, this.configParams.StorePath, this.configParams.StoreIP);
//启动连接
Session tmpSession = this.ConnectPLC();
if (tmpSession.Connected)
{
this.UseOPCUA = true;
}
}
}
catch (Exception ex)
{
//记录结果
string logcontent = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " 监控OPCUA通信连接处理发生错误!原因: " + ex.Message;
BaseApiHandler.RecordLog(logcontent, this.configParams.Logpath, "ConnetOPCUA", this.configParams.RecordBizDataLog);
}
Thread.Sleep(5 * 1000);//延迟秒级别
}
}
基于C#打造的OPCUA客户端应用的更多相关文章
- 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码
本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾 ...
- 基于.NET打造IP智能网络视频监控系统
开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾情奉献:基于.NET打造 ...
- 重温WCF之WCF传输安全(十三)(4)基于SSL的WCF对客户端采用证书验证(转)
转载地址:http://www.cnblogs.com/lxblog/archive/2012/09/20/2695397.html 前一篇我们演示了基于SSL的WCF 对客户端进行用户名和密码方式的 ...
- 基于jQuery打造的选项卡向上弹出jquery焦点图切换特效
基于jQuery打造的选项卡向上弹出jquery焦点图切换特效 鼠标经过标题栏,会出现层特效向上滑动,并且在同时进行幻灯片切换,效果十分不错. 有兴趣的童鞋可以下载看看,在IE6方面兼容性也不错,只有 ...
- 基于jquery打造的网页右侧自动收缩浮动在线客服代码
基于jquery打造的网页右侧自动收缩浮动在线QQ客服代码, 当前比较流行的一款QQ在线jquery特效代码, 代码中还带有IE6下PNG图片透明的特效,如果想研究IE6下PNG透明的同学也可以下载研 ...
- 基于MongoDB打造.Net的分布式Session子系统
基于MongoDB打造.Net的分布式Session子系统 Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式 ...
- 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——收流篇:(一)简介
关于实时流媒体传输的开源库,目前流行的主要有两个:live555和jrtplib. 其中live555将rtp.rtcp和rtsp的传输协议实现集于一身,功能齐全,是个超强的集合体.但是对于嵌入式系统 ...
- 超级好用的前端开发测试Chrome插件-基于REST的Web服务客户端
基于REST的Web服务客户端是一款功能强大的谷歌浏览器插件,使用基于REST的Web服务客户端(模拟REST客户端)可以让用户使用谷歌浏览器模拟REST请求来测试REST风格. 基于REST的Web ...
- XMPP(二)-基于asmack+openfire的安卓客户端(仿QQ)的介绍以及个人心得
关于XMPP第一篇-openfire的搭建写完后,就一直在赶本篇所要介绍的这个基于asmack+openfire的安卓客户端,费了不少精力,因为有不少同学在还在焦急的等待着(自恋了呵呵),所以紧赶慢赶 ...
随机推荐
- 不难懂-----Mock基本使用
一.mock解决的问题 开发时,后端还没完成数据输出,前端只好写静态模拟数据.数据太长了,将数据写在js文件里,完成后挨个改url.某些逻辑复杂的代码,加入或去除模拟数据时得小心翼翼.想要尽可能还原真 ...
- linux关闭swap
#(1)临时关闭swap分区, 重启失效; swapoff -a #(2)永久关闭swap分区 sed -ri 's/.*swap.*/#&/' /etc/fstab 也可以在sysctl.c ...
- ☕【Java深层系列】「并发编程系列」深入分析和研究MappedByteBuffer的实现原理和开发指南
前言介绍 在Java编程语言中,操作文件IO的时候,通常采用BufferedReader,BufferedInputStream等带缓冲的IO类处理大文件,不过java nio中引入了一种基于Mapp ...
- Working hard to know your neighbor's margins:Local descriptor learning loss论文笔记
Abstract 论文提出了一种新的训练方法,受到了 Lowe's matching criterion for SIFT的启发.这种新的loss,要比负责的正则方法更好.把这个新的loss方法结合L ...
- Java反射机制及原理
一.概念 java程序运行时动态的创建类并调用类的方法和属性 二.原理简介 Class<?> clz = Class.forName("java.util.ArrayList ...
- Hbase 项目
需求分析 1) 微博内容的浏览,数据库表设计 2) 用户社交体现:关注用户,取关用户 3) 拉取关注的人的微博内容 表结构 代码实现 1) 创建命名空间以及表名的定义 2) 创建微博内容表 3) 创 ...
- jsp FN 标签库的使用方法
1. 在jsp 导入标签库 <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="f ...
- halcon视觉入门扫盲篇
halcon视觉入门扫盲篇 前言 在公司让我研究视觉的时候,我是两眼一抹黑的.之前完全没有接触过视觉.综合权衡后选择了Halcon,使用的是HDevelop 13 (64-bit). ...
- X000100
P3172 [CQOI2015]选数 gcd 为 \(K\) 不太好办,所以我们先把它转化成 gcd 为 1 的问题: scanf("%d%d%d%d",&n,&k ...
- 「JOI 2014 Final」飞天鼠
「JOI 2014 Final」飞天鼠 显然向上爬是没有必要的,除非会下降到地面以下,才提高到刚好为0. 到达一个点有两种情况:到达高度为0和不为0. 对于高度不为0的情况,显然花费的时间越少高度越高 ...