之前主要是简单的描述了OPC DA的开发,今天在这里整理一下OPC UA协议的相关内容。下面主要按照几个问题的方式来总结OPC UA协议
OPC UA(Unified Architecture,统一架构)是下一代的OPC 标准,通过提供一个完整的,安全和可靠的跨平台的架构,以获取实时和历史数据和时间。
OPC UA基于OPC基金会提供的新一代技术,提供安全,可靠和独立于厂商的,实现原始数据和预处理的信息从制造层级到生产计划或ERP层级的传输。通过OPC UA,所有需要的信息在任何时间,任何地点对每个授权的应用,每个授权的人员都可用。这种功能独立于制造厂商的原始应用,编程语言和操作系统。
a.用过OPC DA的人都知道,这是基于ole/com技术的一套协议,标准接口都是围绕着windows来写的,对windows系统具有强依赖性,因此如果是要将服务做成linux化的话,一直使用opcda会有很大的局限,当然也不是没有办法,也可以做成插拔件的方式(这是我司的导师给我说的,具体还没有做,预计明年会研究一下如何linux化)。
b.既然OPC DA是基于COM/DCOM技术的,就COM/DCOM技术来说,它本身存在着缺陷,开发者需要掌握大量的专业知识,就我现在来说,应该还是未入门的状态,也存在着安全隐患。
需要在防火墙上打开端口,还需要在客户端和服务端都配置DCOM,这里配置的方法就不说了,网上很多教程。(还记得刚刚接触那会不熟悉,第一次转测试时因为测试那边环境没有配好,最后发现就是这个DCOM没配好导致的,然后全team都在等我一个人,那心里愧疚的哟)
c.从opc ua上来看,它的平台中立性可以在任何平台使用,面向未来,易于配置和维护,是基于服务的技术。
d.OPC UA不再是基于分布式组件对象模型DCOM了,而是以面向服务的架构SOA为基础
OPC DA用久了会发现的确不香,而且麻烦,虽然我目前对接了好几套子系统都是基于这个协议的…
OPC UA是有对象模型的,需要在服务端建模,客户端再去访问,访问方法比DA的方式简单很多,后面介绍。
a.通过因特网和通过防火墙的标准化通信-OPC UA使用一种优化的基于TCP的二进制协议完成数据的交换(opc server和服务端的通信方式)。另外支持web服务和http。现在允许在防火墙中打开一个端口,集成的安保机制确保了通过因特网也能够安全通信。
b.防止非授权的数据访问。使用的一种成熟的安保理念,方式非授权访问和过程数据损坏,以及由于不小心的操作带来的错误。 OPC UA安保理念基于world wide web标准,通过用户鉴权、签名和加密传输等项目来实现(这段话忘记在哪看的了,引用于网络)
c.数据具有安全性和可靠性。使用可靠的通信机制、可配置超时、自动错误检查和自动恢复等机制
d.简单一致,OPC UA定义了一种集成的地址空间和信息模型,可以显示过程数据、报警、历史数据以及完成程序调用。信息项被定义成不同类型的对象,彼此之间可以建立关系,在此基础上,OPC UA支持使用复杂的数据结构,这使OPC UA可以完整的描述复杂过程和系统
由多个部分的规范组合而成,为了把设计核心从底层的运算处理和网络传输分离开来。
前面七个部分依次是,思想和概括、安全模型、地址空间模型、服务、信息模型、映射、配置文件,这几个是OPC UA功能的核心部分,这些核心功能定义了OPC地址空间结构和需要操作的服务。第八到十一部分的核心功能是规范访问类型,根据OPC COM规范划分,如DA、A&E、HAD。第十二部分介绍了为OPC UA提供的发现机制,第十三部分介绍聚合数据的方式。
我这里有关于OPC UA的规范,官网应该能找到,如果找不到也可以给我发邮箱我发出来。
引用:引用描述了两个确定节点之间的关系。因此,源节点、目标节点、引用的语义和引用的方向唯一确定一个引用。我们可以把引用看做一个纸箱其他节点的指针,通过保存其他的节点ID来指向另外一个节点。指针可引用不存在于服务器的节点。引用不能够直接访问,只能间接的通过浏览节点访问。引用由引用类型,分为分层次化引用和非层次化引用两个子类型。
对象、变量和方法:
在OPC UA中,最重要的节点类型是对象、变量和方法。对象可以拥有变量和方法,而且可以触发事件。
节点类别为变量的节点代表一个值,客户端可以对这个值进行拂去、写入和订阅;节点类别为方法的节点代表服务器中一个由客户端调用并返回结果的方法。每个方法指定客户端应使用的输入参数和客户端希望得到的结果即输出参数;节点类别为对象的节点用于地址空间结构,对象使用变量对外提供值,对象不像变量一样拥有value属性。
在网上开源找的开源库,站在巨人的肩膀上开发。
a.头文件
头文件直接引用:
#include
#include
#include
#include
头文件中,自定义类直接集成SubscriptionHandler:
class UAClient : public OpcUa::SubscriptionHandler
{
// @todo what you want.
}
b.日志库
该库已经封装了一个日志库,就没有用之前Poco里面的日志库打印:
m_logger = spdlog::stdout_color_mt("opcUAClient");
OpcUa::UaClient m_client(m_logger);
c.连接登陆
直接调用connect接口
m_client.Connect(m_uaendpoint);
d.遍历节点
OpcUa::Node root = m_client.GetRootNode();;
m_logger->info("Root node is:{}", root);
m_logger->info("Child of objects node are:");
OpcUa::Node objects = m_client.GetObjectsNode();
for (OpcUa::Node node : objects.GetChildren())
{
m_logger->info("{}", node);
}
for (OpcUa::Node node : mynode.GetChildren())
{
m_nodeName = node.GetBrowseName().Name;
//省略代码段
OpcUa::Variant v = node.GetValue();
//省略代码段
}
}
数据订阅回调:
void UAClient::DataChange(uint32_t handle, const OpcUa::Node & node, const OpcUa::Variant & val, OpcUa::AttributeId attr)
{
std::map<uint32_t, std::string>::iterator iter = m_mapHandleToName.begin();
for (; iter != m_mapHandleToName.end(); ++iter)
{
if (handle == iter->first)
{
m_mapNameToValue.insert(std::pair<std::string,std::string>(iter->second,val.ToString()));
}
}
}
OPC UA目前了解的不多,明年有项目需求再去进一步的了解和深究,代码段真的只是代码段,是基于项目写的,因为很多东西没加。如果有写的不好或者欠妥的地方,希望多多包含新人并欢迎指正,谢谢!