OPC服务器与客户程序开发指南Word文件下载.docx
《OPC服务器与客户程序开发指南Word文件下载.docx》由会员分享,可在线阅读,更多相关《OPC服务器与客户程序开发指南Word文件下载.docx(35页珍藏版)》请在冰点文库上搜索。
因此OPC技术的出现得到了广大软硬件厂商的支持,并迅速发展。
自从1997年9月发布OPCDA1.0规范以来,经过多年的发展,OPC规范已经被工控领域大多数厂商接受,并成了工控软件的技术标准。
目前OPC规范主要有DA(DataAccess)规范,AE(alarmandevent)规范,HDA(historydataaccess)规范等。
而且随着OPC技术与企业整体信息系统集成的需求变得日益迫切,对OPC技术的跨平台性能和Internet特性提出了更高要求。
为此,OPC基金会开始以XML为基础着手制定一系列新的标准。
2002年3月OPC基金会正式发布了OPCXML-DA规范,并与2004年12月正式发布了OPCXML-DA1.01规范,为OPC进一步提高工业控制系统的互操作性揭开了新的篇章。
本书仅仅以符合DA规范的OPC服务器和客户程序为例介绍OPC技术,对于其它规范的OPC技术,本书未能介绍。
1.1OPC技术的本质——COM/DCOM
随着计算机网络技术的发展,计算机监控系统也普遍的采用了分布式结构,因而系统的异构性是一个非常显著的特点。
OPC技术本质是采用了Microsoft的COM/DCOM(组件对象模型/分布式组件对象模型)技术,COM主要是为了实现软件复用和互操作,并且为基于WINDOWS的程序提供了统一的、可扩充的、面向对象的通讯协议,DCOM是COM技术在分布式计算领域的扩展,使COM可以支持在局域网、广域网甚至Internet上不同计算机上的对象之间的通讯。
COM是由Microsoft提出的组件标准,它不仅定义了组件程序之间进行交互的标准,并且也提供了组件程序运行所需的环境。
在COM标准中,一个组件程序也被称为一个模块,它可以是一个动态链接库,被称为进程内组件(in-processcomponent);
也可以是一个可执行程序(即EXE程序),被称作进程外组件(out-of-processcomponent)。
一个组件程序可以包含一个或多个组件对象,因为COM是以对象为基本单元的模型,所以在程序与程序之间进行通信时,通信的双方应该是组件对象,也叫做COM对象,而组件程序(或称作COM程序)是提供COM对象的代码载体。
COM标准为组件软件和应用程序之间的通信提供了统一的标准,包括规范和实现两部分,规范部分规定了组件间的通信机制。
由于COM技术的语言无关性,在实现时不需要特定的语言和操作系统,只要按照COM规范开发即可。
然而由于特定的原因,目前COM技术仍然是以Windows操作系统为主,在非Windows操作系统上开发OPC,具有很大的难度。
COM的模型是C/S(客户/服务器)模型,OPC技术的提出就是基于COM的C/S模式,因此OPC的开发分为OPC服务器开发和OPC客户程序开发,对于硬件厂商,一般需要开发适用于硬件通讯的OPC服务器,对于组态软件,一般需要开发OPC客户程序。
对于OPC服务器的开发,由于多种编程语言在实现时都提供了对COM的支持,如MicrosoftC/C++,VisualBasic,Borland公司的Delphi等。
但是开发OPC服务器的语言最好是C或者是C++语言。
在本书中选用VisualC++6.0为开发语言。
对于OPC客户程序的开发,可根据实际需求,选用比较合适的,能够快速开发的语言。
1.2OPCDA204规范简述
OPCDA204规范(OPCDataAccessCustomInterfaceSpecification2.04)是2000年9月OPC基金会发布的OPCDA自定义接口规范。
该规范制定了OPC服务器和OPC客户程序的COM接口标准,通过制定标准的接口来实现多个厂家的OPC服务器和OPC客户程序开发。
本书附带OPCDA204规范的WORD文档。
1.2.1OPC客户程序和OPC服务器
一个OPC客户可以连接一个或多个OPC服务器,而多个OPC客户也可以同时连接同一个OPC服务器,如图1.2所示。
图1.2OPC客户程序/OPC服务器关系
1.2.2OPC服务器的对象组成
一个OPC服务器由三个对象组成:
服务器(Server),组(Group),项(Item)。
OPC服务器对象用来提供关于服务器对象自身的相关信息,并且作为OPC组对象的容器。
OPC组对象用来提供关于组对象自身的相关信息,并提供组织和管理项的机制。
OPC组对象提供了OPC客户程序用来组织数据的一种方法。
例如一个组对象代表了一个PLC(可编程控制器)中的需要读写的寄存器组。
一个客户程序可以设置组对象的死区,刷新频率,需要组织的项等。
OPC规范定义了2种组对象:
公共组和私有组。
公共组由多个客户共享,局部组只隶属于一OPC客户。
全局组对所有连接在服务器的应用程序都有效,而私有组只能对建立它的CLIENT有效。
在一个SERVER中,可以有若干个组。
OPC项代表了OPC服务器到数据源的一个物理连接。
数据项是读写数据的最小逻辑单位。
一个OPC项不能被OPC客户程序直接访问,因此在OPC规范中没有对应于项的COM接口,所有与项的访问需要通过包含项的OPC组对象来实现。
简单的讲,对于一个项而言,一个项可以是PLC中的一个寄存器,也可以是PLC中的一个寄存器的某一位。
在一个组对象中,客户可以加入多个OPC数据项。
每个数据项包括3个变量:
值(Value)、品质(Quality)和时间戳(TimeStamp)。
数据值是以VARIANT形式表示的。
图1.3Server/Group/Item关系
这里最需要注意的是项并不是数据源,项代表了到数据源的连接。
例如一个在一个DCS系统中的TAG不论OPC客户程序是否访问都是实际存在的。
项应该被认为是到一个地址的数据。
大家一定要注意项的概念。
不同的组对象里可以拥有相同的项,如组1中有对应于一个开关的ITEMAAA,组2中也可以有同样意义对应于一个开关的ITEMAAA,即同样的项可以出现在不同的组中。
1.2.3OPC接口体系
OPC规范提供两种接口:
自定义接口(theOPCCustomInterfaces),自动化接口(theOPCAutomationinterfaces)。
图1.4OPC接口
如前所述,象所有的COM结构一样,OPC是典型的CLIENT/SERVER结构,OPC服务器提供标准的OPC接口供OPC客户程序访问。
OPC服务器必须提供自定义接口,对于自动化接口,在OPC规范定义中是可选的。
图1.5典型OPC结构
1.3OPC对象接口定义
本节主要对OPC服务器对象和OPC组对象的接口进行简要的介绍。
OPC服务器对象提供一些方法去读取或连接一些数据源。
OPC客户程序连接到OPC服务器对象,并通过标准接口与OPC服务器联系。
OPC服务器对象提供接口(AddGroup)供OPC客户程序创建组对象并将需要操作的项添加到组对象中,并且组对象可以被激活,也可以被赋予未激活状态。
对于OPC客户程序而言,所有OPC服务器和OPC组对象可见的仅仅是COM接口。
下面的两个图例是OPC规范中定义的OPC服务器对象和OPC组对象的COM接口,其中任选的接口均以[]表示。
(注:
任选指开发OPC服务器时,这些接口可以根据实际情况选择实现还是不实现,除任选项外的接口在开发时必须全部实现。
)
图1.6标准OPC服务器对象及接口
IOPCServerPublicGroups,IOPCBrowseServerAddressSpace和
IPersistFile为任选(optional)接口,OPC服务器提供商可根据需要选择是否需要实现。
其它接口为OPC服务器必须实现的接口。
其中:
IOPCServerPublicGroups接口用于对公共组进行管理。
IPersistFile接口允许用户装载和保存服务器的设置,这些设置包括服务器通信的波特率、现场设备的地址和名称等,这样用户就可以知道服务器启动和配置的改变而不需要启动其它的程序。
IOPCBrowseServerAddressSpace允许用户浏览服务器中的有用的组员的数据,为用户提供OPC服务器各个组员的定义列表。
IOPCCommon接口是其它OPC服务器(例如OPC报警与事件服务器)也使用的接口。
通过该接口可为某个特定的客户/服务器对话(session)设置和查询本地标识(LocateID)。
这样,一个客户程序的操作将不会影响其它客户程序。
IConnectionPointContainer接口服务器(OPC服务器对象接口)支持可连接点对象,当OPC服务器关闭时需要通知所有的客户程序释放OPC组对象和其中的OPC组员,此时可利用该接口调用客户程序方的IOPCShutdown接口实现服务器的正常关闭。
IOPCServer接口及成员函数主要用于对组对象进行创建、删除、枚举和获取当前状态等操作。
是OPC服务器对象的主要接口。
接口及成员函数定义为:
图1.7标准OPC组对象及接口
IOPCItemMgt接口及成员函数用于OPC客户程序添加、删除和组对象中组员等控制操作。
IOPCGroupStateMgt接口及其成员函数允许OPC客户程序操作或获取用户组对象的全部状态(主要是组对象的刷新率和活动状态,刷新率的单位为毫秒)。
IOPCPublicGroupStateMgt为任选接口,用于将私有组对象(privategroup)转化为公有组对象(publicgroup),这个接口一般不用,在很多商业的OPC服务器中,此接口都没有开发。
可选接口IOPCAsyncIO和IdataObject接口用于异步数据传输(在OPC数据访问规范1.0中定义,现在其功能已经被IOPCAsyncIO2和IConnectionPointContainer接口取代)。
IOPCSyncIO用于同步数据访问。
IOPCAsyncIO2用于异步数据访问。
这两个接口是数据访问规范进行数据访问最重要的接口。
有关OPC服务器对象和OPC组对象的COM接口详细定义请看OPC规范定义,除在开发实例中用到的COM接口,其它接口本文不再详述。
1.4OPC同步异步通讯
OPCDA规范规定了两种通讯方式:
同步通讯和异步通讯。
这两种通讯方式与常见的串口同步通讯、异步通讯以及以太网的同步通讯、异步通讯的功能差不多。
同步通讯时,OPC客户程序对OPC服务器进行相关操作时,OPC客户程序必须等到OPC服务器对应的操作全部完成以后才能返回,在此期间OPC客户程序一直处于等待状态,如进行读操作,那么必须等待OPC服务器完成读后才返回。
因此在同步通讯时,如果有大量数据进行操作或者有很多OPC客户程序对OPC服务器进行读、写操作,必然造成OPC客户程序的阻塞现象。
因此同步通讯适用于OPC客户程序较少,数据量较小时的场合。
异步通讯时,OPC客户程序对服务器进行相关操作时,OPC客户程序操作后立刻返回,不用等待OPC服务器的操作,可以进行其他操作。
当OPC服务器完成操作后再通知OPC客户程序,如进行读操作,OPC客户程序通知OPC服务器后离开返回,不等待OPC服务器的读完成,而OPC服务器完成读后,会自动的通知OPC客户程序,把读结果传送给OPC客户程序。
因此相对于同步通讯,异步通讯的效率更高,适用于多客户访问同一OPC服务器和大量数据的场合。
OPC的异步通讯有四种方式:
数据订阅,客户端通过订阅方式后,服务器端将变化的数据通过回调传送给客户程序。
异步读,返回操作结果和数据值。
异步写,返回操作结果,成功、失败。
异步刷新,异步读所有Item的值
1.5OPC服务器开发方式
OPC服务器本身就是一个可执行程序,该程序以一定的速率不断地同物理设备进行数据交互。
服务器内有一个数据缓冲区,其中存有最新的数据值,数据质量戳和时间戳。
OPC数据服务器的设计与实现是一个较为复杂与繁重的任务,设计者既需要熟悉OPC规范,同时也必须掌握相应的硬件产品特性。
OPC数据服务器大致可以分解为不同的功能模块。
OPC对象接口管理模块,Item数据项管理模块以及服务器界面和设置等等。
一个设备的OPCServer主要有两部组成,一是OPC标准接口的实现,二是与硬件设备的通信模块。
虽然COM技术本质上具有语言无关性,可以用各种语言开发,但由于最适合COM开发的语言仍然是C++,因此一般都选择采用VisualC++进行开发。
目前用VisualC++开发COM组件主要有三种方式:
使用COMSDK直接开发COM组件;
通过MFC提供的COM支持实现COM组件;
通过ATL来实现COM组件。
此外,目前国内外很多的工控软件厂商也推出了一系列的OPC快速开发工具包,使用专门的OPC开发工具包,开发者只需具备基本的编程基础即可快速上手,无需掌握ATL,COM/DCOM,也无需了解OPC技术的细节,而且大多数的OPC开发工具都支持多种常用编程语言,如VB,VC等。
http:
//www.opc-网站也提供OPC开发工具,有兴趣的读者可以到http:
//www.opc-网站下载DEMO开发工具或者与QQ:
41063473联系购买事宜。
//www.opc-)
建议所有的学生或有志向的开发人员可以尝试独立开发OPC服务器,如果是公司使用,建议购买OPC服务器开发工具。
重点:
何为OPC?
OPCDA有哪些对象?
OPCDA有哪些接口?
OPCDA的通讯方式?
OPCDA的开发方式?
(工控帮http:
//www.opc-)
第2章ATL简介
ATL
类厂
接口
标识符
IDL
组件
聚合
双重接口
连接点
事件
注册
属性方法客户程序
VisualC++从4.0版本就已经提供全面的COM支持,尤其在5.0和6.0版本中,不仅MFC类库提供COM应用的支持,而且VisualC++的集成开发环境VisualStudio也为COM应用提供了各种向导支持,并且,VisualC++还提供了另一套模板库ATL专门用于COM应用程序的开发。
在上一章中介绍了采用VisualC++进行OPC服务器开发的几种方式,因为ATL是专为COM应用程序开发,因此本书的OPC服务器开发采用了ATL的模式,在本章中首先对ATL进行简要介绍,并以实际例子介绍如何进行ATL编写COM组件。
ATL(ActiveTemplateLibrary)是VisualC++提供的一套基于模板的C++类库,利用这些模板类,开发人员可以快速的开发COM组件程序。
所以说ATL专门针对于COM应用开发的,它内部的模板类实现COM的一些基本特征,比如一些基本COM接口IUnknown,IClassFactory,IDispatch等,也支持COM的一些高级特性,如双接口(dualinterface)、连接点(connectionpoint)、Activex控制等。
ATL最初的设计是快速的开发小型的组件,ATL2.0版本添加了模板库用来支持可视化的控件开发。
ATL所具有的特点:
•包含所有C++的功能。
•无需运行库,除非你想使用它。
•引用计数。
•高水平的对象和接口实现方法。
•类厂自动操作,对象创造,接口查询。
ATL开发应用程序并不像开发MFC应用程序那样容易。
但VisualStduio提供某种帮助使开发者迅速开发应用程序。
可利用ATLCOMWinzard(活动模板库组件向导)和ATLObjectWizard(活动模板库对象向导)开发ATL应用程序。
从目前介绍ATL技术的书籍来看,国内的书籍较少,本章主要通过介绍如何创建一个ATL应用程序来使大家对ATL技术有一定的了解,如果读者了解ATL,可以略过此章。
2.1COM基础
本节主要对COM的两个基本概念(接口,组件)做简要介绍。
2.1.1COM
图2.1接口结构
从理论上讲,完整的COM编程系统是基于接口的。
从技术上讲,接口是包含了一组函数的数据结构,通过这组数据结构,客户代码可以调用组件对象的功能。
接口定义了一组成员函数,这组成员函数是组件对象暴露出来的所有信息,客户程序利用这些函数获得组件对象的服务。
需要注意的是在接口成员函数中,字符串变量必须用Unicode字符指针,COM规范要求使用Unicode字符,而且COM库中提供的COMAPI函数也使用Unicode字符。
所以如果在组件程序内部使用到了ANSI字符的话,则应该进行两种字符表达的转换。
当然,在即建立组件程序又建立客户程序的情况下,可以使用自己定义的参数类型,只要它们与COM所能识别的参数类型兼容。
这里需要特别注意的是COM需要使用Unicode字符。
COM接口可以分为以下两类:
▪
标准接口
自定义接口
标准接口之IUnknown,是所有接口的基接口。
自定义接口也是基于IUnknown接口。
所有的COM组件都必须以这个接口为基础。
IUnknown提供了两个非常重要的特性,一个用于组件对象的生命周期管理,也可以查询被组件对象使用的其他接口。
客户程序只能通过接口与COM对象进行通信,虽然客户程序可以不管对象内部的实现细节,但它要控制对象的存在与否。
如果客户还要继续对对象进行操作,则它必须保证对象能一直存在于内存中;
如果客户对象的操作已经完成,以后不再需要该对象了,则它必须及时地把该对象释放掉,以提高资源的利用率。
IUnknown引入了“引用计数”方法,可以有效地控制对象的生存期。
另一方面,如果一个COM对象实现了多个接口,在初始时刻,客户程序不太可能得到该对象的所有接口指针,它只会拥有一个接口指针。
如果客户程序需要其它的指针,则可利用IUnknown的“接口查询”方法来完成接口之间的跳转。
IUnknown的IDL定义:
interfaceIUnknown
{
HRESULTQueryInterface([in]REFIIDiid,[out]void**ppv);
ULONG
AddRef(void);
Release(void);
}
IUnkown的C++定义:
classIUnknown
virutalHRESULT_stdcallQueryInterface(constIID&
iid,void**ppv)=0;
virtualULONG
_stdcallAddRef()=0;
virutalULONG
_stdcallRelease()=0;
标准接口之IDispatch,此接口用于脚本语言(如VisualBasic)访问组件。
当脚本语言调用组件对象的方法时,此接口查询函数的地址并执行。
标准接口之IClassFactory(类厂)接口用于创建新的COM对象的实例。
类厂(classfactory)是COM对象的生产基地,COM库通过类厂创建COM对象;
对应每一个COM类,有一个类厂专门用于该COM类的对象创建操作。
类厂本身也是一个COM对象,它支持一个特殊的接口IClassFactory:
classIClassFactory:
publicIUnknown
{
virtualHRESULT_stdcallCreateInstance(IUnknown*pUnknownOuter,
constIID&
virtualHRESULT_stdcallLockServer(BOOLbLock)=0;
}
如果你还没有学过COM,那么你来创建一个组件的时候很可能会采用C++的new操作符,这样的话会返回一个奇怪的错误。
这也是一个非常常见的ATL错误,一个初学者不太理解的错误。
实际上,创建一个对象,需要调用CoCreateInstance来创建一个COM对象的实例。
在这里要注意的是创建COM对象不是用new操作符。
在后面的章节中同样可以看到释放一个对象时,不能用delete,而是要通过Release接口来释放对象。
自定义接口的目的是提供更多的功能给用户,开发者可以自己定义基于IUnknown的接口提供更多的功能。
COM标识符UUID/GUID用来标识组件,通过唯一标识行UUID来唯一标识组件,如同身份证的意义,可以在系统中标识COM组件。
在COM中,UUID是指全局唯一标识符GUID。
GUID分为CLSID、IID和LIBID三类。
COM规范采用了128位全局唯一标识符GUID来标识对象和接口,这是一个随机数,并不需要专门机构进行分配和管理。
因为GUID是个随机数,所以并不绝对保证唯一性,但发生标识符相重的可能性非常小。
从理论上讲,如果一台机器每秒产生10000000个GUID,则可以保证(概率意义上)的3240年不重复。
接口描述语言IDL。
COM规范在采用OSF(开放软件基金会)的DCE(分布式计算环境)规范描述远程调用接口IDL(interfacedescription