基于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的安卓客户端,费了不少精力,因为有不少同学在还在焦急的等待着(自恋了呵呵),所以紧赶慢赶 ...
随机推荐
- vue传参子传父
vue子传父用$emit实现 1.文件目录结构 2.parent父组件内容 <template> <div class="wrap"> <div> ...
- 【Java】代码块
代码块 代码块的作用:用来初始化类.对象 代码块如果有修饰的话,只能使用static 分类:静态代码块.非静态代码块 静态代码块 static{ } 内部可以有输出语句 随着类的加载而执行,而且只执行 ...
- 微服务探索之路02篇liunx ubuntu服务器部署k8s(kubernetes)-kubernetes/dashboard
本章介绍所需环境:ubuntu18.04,建立在上一篇微服务探索之路01篇已经安装了docker的基础上. 1 替换k8s镜像源为国内镜像 进入目录 cd /etc/apt/sources.list. ...
- 集合框架-工具类-JDK5.0特性-静态导入
1 package cn.itcast.p4.news.demo; 2 3 import java.util.ArrayList; 4 //import java.util.Collections; ...
- 网页中的一键加QQ群、唤起QQ群聊天窗口
1.进入QQ群官网: https://qun.qq.com 2. 登陆QQ账号,点击加群组件 3. 左侧选择指定的群,右侧会给出一键加群的链接 4. 浏览器访问刚才复制的链接,点击 打开腾讯QQ 5. ...
- VUE3 之 组件间事件通信 - 这个系列的教程通俗易懂,适合新手
1. 概述 相关定律告诉我们:这个世界上的任何事物之间都会存在一定联系,"城门失火,殃及池鱼"就是一个很好的例子.因此如果我们能够尽早发现这些看不见的联系,就能很好的解决更多遇见的 ...
- maven项目 子父级工程。
一 .什么是 maven 子父级工程? 建立一个maven项目,然后在该项目 下创建一个module,子级的maven,他继承于父级项目. 1.新建立 maven项目,file ------new- ...
- 计算机网络再次整理————tcp例子[五]
前言 本文介绍一些tcp的例子,然后不断完善一下. 正文 服务端: // See https://aka.ms/new-console-template for more information us ...
- js添加元素代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Typora快捷键 shortcuts-windows
Typora快捷键 shortcuts-windows 快捷键 作用 ctrl+ ctrl- 字体大小调节 ctrl + shift + ` 行内代码 alt+shift+5 删除线 ctrl+shi ...