研究C#程序与基于COM的OPC数据存取服务器交换数据
摘要:研究了OPC NET COM自动化包装器所封装的COM编排技术和OPC NET应用程序接口内的设计模式。在其基础上使用C#语言编写了一个基于.NET的OPC客户程序,与基于COM的OPC数据存取服务器交换数据。有效地实现了将遵循OPC规范的代码从COM平台移植到.NET平台。
关键词:C#;COM编排;数据存取服务器;设计模式
Study C# program to exchange data with COM based OPC data access server
He Hai-jiang
( Department of Computer Science of Hunan Economic Management College ,Hunan Changsha 410004 )
Abstract: The marshal technique from OPC NET COM Wrapper and design patterns from OPC NET API are researched. An OPC client software based on .NET is built on the basis of these technique with C# language,it is employeed to exchange data with OPC data access server based on COM.It is effectively realized to migrate the code following OPC specifications from COM plantform to .NET plantform.
Key Words: C#;COM marshal;data access server;design pattern
C#是微软为.NET平台量身订作的新程序语言,特别适合组件的开发,当前软件工业中许多产品的新版本逐步转移到的.NET平台。OPC是工业软件中广泛采用的数据交换协议,许多数据采集设备都要求提供实现OPC数据存取规范的服务器,和上层软件交换数据。因此研究在C#中实现OPC有很大的现实意义。OPC数据存取规范从1.0版本到2.05,再到3.0版本,微软的分布式应用软件开发平台从COM到.NET,导致了许多的不兼容问题。笔者从事的工业过程数据仓库系统中就存在这样的情况,许多供应商的OPC服务器是在COM平台开发的,而应用软件需要在.NET框架下实现,要求和已经安装好的那些COM平台服务器通讯,必须解决如何使OPC应用在两个平台间无缝迁移。
COM和.NET是两个差别很大的分布式应用软件开发平台,如果要在.NET 应用中使用COM对象,需要通过RCW(runtime-callable wrapper, 运行环境可调用包装器)在可管理的.NET代码和未托管的COM代码之间生成一个代理。Visual Studio.NET提供了一个工具类型库导入器TlbImp.exe,可以方便地提取COM程序的信息。实现了自动化接口的OPC服务器可以使用这种方法。但大多数的OPC服务器只实现定制接口,该方法无法实现,需要手工编排COM中的IDL(Interface Definition Language,接口定义语言),工作量非常大。编排过程中会遇到包括数据类型转换、接口实现、参数传递等许多问题的困扰,自动化软件要求高可靠性,要编写这样的软件,软件测试和维护的工作量很大。现在OPC基金会对会员提供了OpcRcw动态链接库,OPC NET COM 包装器和OPC NET API,前两者完成了前述的工作,后者将OPC复杂的规范封状成简单易用的C#类。本文分析了这些组件的核心代码,在此两种技术的基础上,建立一个.NET框架的OPC客户软件,与基于COM的OPC数据存取服务器交换数据。文中提供一个应用实例,代码全部使用C#实现,分五个步骤说明。
1 组件核心内容
OPC基金会提供的这些组件,包括源代码和部分文档,但文档部分比较简单,在软件设计过程中,大量使用了抽象工厂模式和策略设计模式。要理解这些设计模式,需要阅读这方面的书籍,设计模式经典书为Erich Gamma 等四人所著《Design Patterns Elements of Reusable Software 》。文章将OPC客户端的典型应用逐一列出,读者理解文章内容后,无需花费大量时间去读懂OPC基金会的这些代码,就比较容易编写相应的程序。
组件内实现了各种类型,各种规范的OPC服务器。如图一所示,采用抽象工厂模式,通过使用接口IFactory和IServer增加了代码的可重用性。
命名空间Opc下包括:接口IServer为所有OPC服务提供公共功能;接口IFactory为OPC服务实例化提供公共功能;IDiscovery搜索网络中计算机上已安装的OPC服务器;类Server,实现接口IServer,所有OPC服务的基础类;类Factory,实现接口IFactory,所有实例化工厂的基础类;还有类ItemIdentifier、Type等。
命名空间Opc.Da下包括:接口IServer,为所有数据存取服务提供公共功能;接口ISubscription,对数据存取服务器的订阅,包含一系列项,相当于规范中的组;类Item,实现一个项的功能;类Server,实现本命名空间下的接口IServer,并继承自Opc下的类Server,提供所有的数据存取服务功能;还有类Subscription、Property等。
命名空间OpcCom下包括:类Factory, 实例化基于COM的OPC服务;还有类Interop等。命名空间OpcCom.Da20下包括:类Server,实现基于COM的OPC数据存取服务,类Subscription实现2.0版本服务器的订阅功能。
2服务器的枚举和连接
遵照Visual Studio.NET的要求,要使用这些组件,如图二所示,还需要将组件OpcNetApi.dll和OpcNetCom.dll加入引用。在程序中使用using,加入这些命名空间。
using Opc;
using Opc.Da;
using OpcCom;
下面的代码用来浏览某台计算机上已安装的数据存取规范服务器。
private Opc.IDiscovery m_discovery = new OpcCom.ServerEnumerator();//定义枚举基于COM服务器的接口,用来搜索所有的此类服务器。
Opc.Server[] servers = m_discovery.GetAvailableServers(daver, host, null);
//daver表示数据存取规范版本,Specification.COMDA_20等于2.0版本。
//host为计算机名,null表示不需要任何网络安全认证。
if (servers != null){
foreach (Opc.Da.Server server in servers) {
//server即为需要连接的OPC数据存取服务器。
}
}
图二 添加两个组件的引用
下面的代码建立与某服务器的连接。
private Opc.Da.Server m_server=null;//定义数据存取服务器
…//从前文浏览到的某一个OPC数据存取服务器赋给m_server。
try{
m_server.Connect();//建立连接。
…
}
catch (Exception f){//捕获错误,提高软件的健壮性。
MessageBox.Show(f.Message);
}
3 增加、删除组和项
OPC NET API使用类Subscription来封装组的操作,下面的代码第一段增加一个组,第二段删除一个组。
Opc.Da.Subscription subscription = null;//定义一个对服务器的订阅者
Opc.Da.SubscriptionState state = new Opc.Da.SubscriptionState(); //订阅者状态,相当于OPC规范中组的参数,为方便说明,后段用组代替订阅者。
state.Name = "仪表";//组名
state.ServerHandle = null;//服务器给该组分配的句柄。
state.ClientHandle = Guid.NewGuid().ToString();//客户端给该组分配的句柄。
state.Active = true;//激活该组。
state.UpdateRate = 1000;//刷新频率为1秒。
state.Deadband = 0;// 死区值,设为0时,服务器端该组内任何数据变化都通知组。
state.Locale = null;//不设置地区值。
subscription = (Opc.Da.Subscription)m_server.Crea