OPC简介及OPC DA 服务器的设计与实现
服务器选择采用连续存储的方式。该方式可以随机存取数据,但存取数据的数量不宜过大,如果需要存取较大数量的数据项,则推荐采用哈希存储方式。对于每个数据项,都包含有三个基本属性:数值(Value),时间戳(Time Stamp)和数据品质(Quality)。从数据源中访问到的数据项将按照线性方式存储到连续的内存区域中;每次对缓存区的访问都需要进行加锁,以防止出现同时进行读操作和写操作。 2.3 轮询方式对数据源进行访问: 由于服务器是单独不断从数据源读取数据,因此可以采用单独的线程,按时间轮询的方式,每隔一段时间对数据源进行访问,这个时间也就成为服务器支持的最短数据访问时间。服务器的主要工作流程: (1) 每隔一段时间进行轮询操作; (2) 如果扫描时间到,访问数据源;否则,至(3);如果有订阅请求,回调订阅函数; (3) 如果有刷新请求,回调刷新函数;如果有异步读数据请求,读取数据并回调异步读函数;如果有异步写请求,将数据写入外部设备; (4) 返回(1); 服务器中该循环的主要功能,主要用来进行异步数据存取,订阅及刷新。而对于同步访问等操作,由于需要服务器立即存取数据然后返回结果,因此其实现并不在该主循环中,而是针对其接口单独编写一个类,用来实现同步存取接口函数的功能。 2.4 OPC DA 的数据访问方式 OPC DA 对数据的访问主要分为以下几种:同步读,异步读,订阅和数据刷新;对数据源的操作又可以分为直接从设备读取和从Cache 中读取。这两者的组合构成了对数据源的访问规则,OPC 标准对访问规则进行了详细的描述。在这几种数据访问中,同步读接口可以实现少量,快速的数据读取,异步读则是提交一个请求,然后返回,等服务器完成数据读取后回调函数。与同步读相比,异步读更能提高OPC Client 的使用效率,防止OPC 服务器尚未访问到数据时,造成客户端的等待。订阅异步读大致相同,每当访问数据源后自动将数据提交给客户端。 图 2 OPC 服务器中采用的可连接对象结构模型 在 OPC DA2.0 和OPC DA3.0 中的异步通讯机制中,使用到了连接点容器/连接点接口[1],取代了原来OPC DA1.0 中的直接注册/回调的模式。能够更灵活的支持多个连接点和连接。在可连接对象模式中,每个可连接对象可以包含多个连接点,每个连接点支持一种回调接口;每个连接点上可以连接多个客户端;回调接口由客户端实现,可连接对象通过回调函数于客户端进行交互。 在 OPC DA 服务器中,可连接对象包括Server 对象和Group 对象两种,Server 对象只支持一个IOPCShutdown 回调接口,而异步数据交换等重要的功能位于Group 对象中。在OPC 组对象中,包含一个连接点对象,该对象支持IOPCDataCallback 回调接口,连接点可以连接多个客户端,当异步访问完成时,服务器同过可连接对象通过调用标准规定的回调函数,通知每个已经注册的客户端。 2.5 基于适配器模式的数据采集 OPC DA 服务器的最重要功能,就是从外部设备读取数据。由于数据源的多样性,可以是磁盘映射的数据文件,串口或者是专门的数据采集卡。为了设计一个通用的架构,便于以后升级或访问其他不同类型的数据源。一个可行的解决方法就是,添加一个适配层,设计相应的数据访问接口,对有不同数据格式的采集,写入等操作,都从该接口继承,从而针对不同的数据采集方式完成相应的功能。这样,使服务器在整体不需改变的情况下,能够适应多种数据源的情况。其大致的结构如下图所示 图 3 使用适配器模式的IOPCItem 接口 IOPCItem 接口:该接口定义了对外部数据进行访问的虚函数,包括读取(ReadValue),和写入(WriteValue)函数;在进行二次开发时,需针对不同的数据源需要具体实现。当一个组对象扫描该组成员项,进行数据访问时,它将直接调用IOPCItem 接口。该接口是一个虚基类,其具体实现与外部数据源有关;对于将要访问的外部设备,其存取数据的格式和驱动可能不同;IOPCItem 接口对此并不作具体规定,只是定义了虚函数,用来读取和写入数据;其具体的编码实现需要由OPC DA 服务器将要访问的外部设备决定。这样,将数据访问同具体的数据源分开,减少了耦合,使同一服务器架构可以满足多种业务需求。 OPC 客户端对在进行数据访问时,是以组为单位的,每个组中可以加入客户端需要访问的数据项,具体的访问交互过程如下: (1) OPC DA 客户端查找并访问一个OPC DA 服务器,此时在OPC DA 服务器端,创建一个Server 对象,并返回一个接口指针; (2) 客户端由返回的指针找到接口IOPCServer,通过IOPCServer::AddGroup()函数
3 OPC DA 服务器与客户端数据访问的交互过程