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客户端应用的更多相关文章

  1. 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码

    本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载. 开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾 ...

  2. 基于.NET打造IP智能网络视频监控系统

    开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码   开源倾情奉献系列链接 开源倾情奉献:基于.NET打造IP智能网络视频监控系统(一)开放源代码 开源倾情奉献:基于.NET打造 ...

  3. 重温WCF之WCF传输安全(十三)(4)基于SSL的WCF对客户端采用证书验证(转)

    转载地址:http://www.cnblogs.com/lxblog/archive/2012/09/20/2695397.html 前一篇我们演示了基于SSL的WCF 对客户端进行用户名和密码方式的 ...

  4. 基于jQuery打造的选项卡向上弹出jquery焦点图切换特效

    基于jQuery打造的选项卡向上弹出jquery焦点图切换特效 鼠标经过标题栏,会出现层特效向上滑动,并且在同时进行幻灯片切换,效果十分不错. 有兴趣的童鞋可以下载看看,在IE6方面兼容性也不错,只有 ...

  5. 基于jquery打造的网页右侧自动收缩浮动在线客服代码

    基于jquery打造的网页右侧自动收缩浮动在线QQ客服代码, 当前比较流行的一款QQ在线jquery特效代码, 代码中还带有IE6下PNG图片透明的特效,如果想研究IE6下PNG透明的同学也可以下载研 ...

  6. 基于MongoDB打造.Net的分布式Session子系统

    基于MongoDB打造.Net的分布式Session子系统 Taobao有她自己的分布式session框架,.net阵营也不能落后了,在下做了个基于MongoDB的支持最多26台MongoDB的分布式 ...

  7. 一个基于JRTPLIB的轻量级RTSP客户端(myRTSPClient)——收流篇:(一)简介

    关于实时流媒体传输的开源库,目前流行的主要有两个:live555和jrtplib. 其中live555将rtp.rtcp和rtsp的传输协议实现集于一身,功能齐全,是个超强的集合体.但是对于嵌入式系统 ...

  8. 超级好用的前端开发测试Chrome插件-基于REST的Web服务客户端

    基于REST的Web服务客户端是一款功能强大的谷歌浏览器插件,使用基于REST的Web服务客户端(模拟REST客户端)可以让用户使用谷歌浏览器模拟REST请求来测试REST风格. 基于REST的Web ...

  9. XMPP(二)-基于asmack+openfire的安卓客户端(仿QQ)的介绍以及个人心得

    关于XMPP第一篇-openfire的搭建写完后,就一直在赶本篇所要介绍的这个基于asmack+openfire的安卓客户端,费了不少精力,因为有不少同学在还在焦急的等待着(自恋了呵呵),所以紧赶慢赶 ...

随机推荐

  1. Android一句话 | View事件分发

    View中,无论是down,move,还是up,事件都是这样传递的:由dispatchTouchEvent到onTouch,再到onTouchEvent,click是在onTouchEvent中的. ...

  2. Android官方文档翻译 二 1.Building Your First App

    Building Your First App 创建你的第一个App项目 Dependencies and prerequisites 依赖关系和先决条件 * Android SDK * ADT Pl ...

  3. (2)用Micropython将ESP32数据上云

    之前我们尝试过直接把LED点亮并且闪烁. 今天尝试一下将LED的开关状态上云,并可以通过云来进行数据下发. 数据要上云,首先开发板要联网. 首先我们会用 Python的network 库, 在netw ...

  4. 计算机视觉3-> yolov5目标检测1 |从入门到出土

    本来就想着是对自己第一次跑yolov5的coco128的一个记录,没想到现在准备总结一下的时候,一方面是继续学习了一些,另一方面是学长的一些任务的要求,挖出了更多的东西,所以把名字改为了"从 ...

  5. 论文解读GALA《Symmetric Graph Convolutional Autoencoder for Unsupervised Graph Representation Learning》

    论文信息 Title:<Symmetric Graph Convolutional Autoencoder for Unsupervised Graph Representation Learn ...

  6. Servlet-请求的分发处理

    1,HelloServlet类中 2,a.html中

  7. 什么是HTTP? HTTP 和 HTTPS 的区别?

    转载地址: 面试官:什么是HTTP? HTTP 和 HTTPS 的区别? 一.HTTP HTTP (HyperText Transfer Protocol),即超文本运输协议,是实现网络通信的一种规范 ...

  8. 大厂面试:一个四年多经验程序员的BAT面经(字节、阿里、腾讯)

    前言 上次写了篇欢聚时代的面经,公众号后台有些读者反馈说看的意犹未尽,希望我尽快更新其他大厂的面经,这里先说声抱歉,不是我太懒,而是项目组刚好有个活动要赶在春节前上线,所以这几天经常加班,只能工作之余 ...

  9. 「数据结构」Link-Cut Tree(LCT)

    #1.0 简述 #1.1 动态树问题 维护一个森林,支持删除某条边,加入某条边,并保证加边.删边之后仍然是森林.我们需要维护这个森林的一些信息. 一般的操作有两点连通性,两点路径权值和等等. #1.2 ...

  10. CICD流程

    1.开发者git提交代码至gitlab仓库 2.jenkins从gitlab拉取代码,触发镜像构建 3.镜像上传至harbor私有仓库 4.镜像下载至执行机器--k8s node kubelet 5. ...