OpenDDS

OpenDDS简介

Don Busch,首席软件工程师兼合作伙伴
Object Computing,Inc.(OCI)

介绍
分布式实时应用程序有时以数据为中心而不是以服务为中心,这意味着分布式系统中参与者的主要目标是分发应用程序数据,而不是访问共享服务。应用程序数据的提供者和/或使用者的集合在设计时可能是未知的,并且可能会在应用程序的整个生命周期内发生变化。通常,以发布/订阅通信模型而不是请求/响应模型最有效地实现以数据为中心的范例。

用于实时系统的OMG 数据分发服务(DDS)解决了以数据为中心的分布式应用程序的性能要求和实时性要求。DDS增加了分布式实时系统开发人员可以使用的发布/订阅选项的范围。为了方便起见,使用OMG接口定义语言(IDL)定义DDS接口。但是,大多数细节留给实现,最重要的是如何在发布者和订阅者之间进行数据传输。DDS实现者决定将底层数据通过TCP,UDP,UDP多播,共享内存等从发布者移动到订阅者的基础通信机制。使用CORBA或IIOP协议不需要DDS规范的实现。将数据从发布者传输到订阅者。

OpenDDS是OMG数据分发服务规范的开源C ++实现。OpenDDS包含基于文件的配置机制。通过配置文件,OpenDDS用户可以配置发布者或订阅者的传输,调试输出,内存分配,DCPSInfoRepo代理进程的位置以及许多其他设置。《OpenDDS开发人员指南》的“配置”一章中介绍了完整的配置设置集。

在本文中,我们涵盖以下主题:

OMG DDS的OpenDDS实现
DDS架构
股票报价员示例
IDL类型
发行人
订户
订户的听众
建立发布者和订阅者
配置股票报价器
通过TCP传输运行股票报价器
通过UDP传输运行股票报价器
摘要
参考资料

OMG DDS的OpenDDS实现

OpenDDS利用可插拔的传输体系结构,通过应用程序开发人员选择的传输和封送实施实现数据传输。从概念上讲,该体系结构借鉴了TAO的可插入协议框架。OpenDDS当前支持TCP和UDP点对点传输以及不可靠和可靠的多播,并使用高性能的封送处理实现。

这种可插拔的传输体系结构允许DDS用户基于所需的传输以及应用程序部署的同质或异质性质来优化DDS安装。可以做出这些选择而不会影响应用程序代码本身。
在这里插入图片描述

封送处理代码由专用的OpenDDS IDL编译器生成。单个单独的DCPS信息存储库(DCPSInfoRepo)流程充当中央票据交换所,将发布者和订阅者联系在一起。在幕后,OpenDDS使用CORBA与DCPSInfoRepo流程进行通信, 以关联发布者和订阅者。发布者和订阅者之间的数据传输直接在发布和订阅过程之间进行。OpenDDS为RB和在发送或接收DDS数据时发生的非CORBA I / O创建自己的线程。

DDS架构

OMG数据分发服务规范将DDS分为两个单独的体系结构层。较低的层是以数据为中心的发布和订阅(DCPS)层,其中包含到发布/订阅通信机制的类型安全接口。上层是数据本地重构层(DLRL),它使应用程序开发人员可以在DCPS层之上构建本地对象模型,从而使应用程序免受DCPS知识的影响。每一层都有自己的概念和使用模式集,因此可以分别讨论这两层的概念和术语。

以数据为中心的发布和订阅-DCPS

DCPS层负责有效地将数据从发布者分发到感兴趣的订阅者。它 在发送方使用发布者和数据写入器 ,在接收方使用订户和数据读取器的概念来实现。DCPS层由一个或多个数据域组成,每个数据域都包含一组通过DDS进行通信的参与者(发布者和订阅者)。每个实体(即发布者或订阅者)都属于一个域。每个进程在其所属的每个数据域中都有一个域参与者。

在任何数据域中,数据都是由主题标识的,该主题是特定于类型的域段,允许发布者和订阅者明确地引用数据。在域中,主题将唯一的主题名称,数据类型和一组服务质量(QoS)策略与数据本身相关联。每个主题仅与一种数据类型相关联,尽管许多不同的主题可以发布相同的数据类型。发布者的行为由与特定数据源的发布者,数据写入者和主题元素相关联的QoS策略确定。同样,订户的行为由与订户,数据读取器和特定数据接收器的主题元素相关联的QoS策略确定。
在这里插入图片描述

有关DCPS术语的更多信息,请参见《OpenDDS开发人员指南》。

DDS规范定义了许多服务质量(QoS)策略,应用程序可使用这些策略来指定其可靠性,资源使用,容错以及对服务的其他要求。参与者指定他们从服务中需要的行为;服务决定如何实现这些行为。这些策略可以应用于各种DCPS实体(主题,数据写入器,数据读取器,发布者,订阅者和域参与者),尽管并非所有策略对所有类型的实体都有效。

订阅者和发布者通过报价请求范例协作指定QoS策略。发布者向所有订阅者提供一套QoS策略。订户请求其所需的QoS策略集。然后,DDS实现会尝试将请求的策略与提供的策略进行匹配。如果策略一致,则发布和订阅将匹配。

OpenDDS支持全套DCPS服务质量(QoS)策略,包括:

QoS政策 描述
活泼 控制活动性检查,以确保系统中预期的实体仍处于活动状态
可靠性 确定是否允许该服务删除样本
历史 控制实例的值发生变化,然后将其传达给所有订阅服务器,该实例发生了什么情况
资源限制 控制服务可用于满足其他QoS要求的资源

有关服务质量策略的更完整列表和更详细的服务质量定义,请参阅对象管理组的DDS白皮书简介附录A。

数据本地重建层-DLRL

数据本地重建层(DLRL)是DCPS之上的面向对象层。DLRL对象是具有一个或多个共享属性的本机语言(即C ++)对象。每个DLRL类都映射到一个或多个DCPS主题。每个共享属性值都映射到主题数据类型的字段,并且其值通过DCPS分布在整个应用程序中。DLRL参与者通过修改DLRL对象将数据与应用程序的其余部分进行通信,从而发布有关主题的数据样本。DLRL共享属性可以是简单的值或结构,对另一个DLRL对象的引用或这些对象的集合(列表,映射)。DLRL支持复杂的对象图和DLRL对象之间的复杂关系。

开发人员负责确定DCPS实体如何映射到DLRL对象。使用IDL值类型在OMG接口定义语言(IDL)中指定模型。映射在概念上类似于对象关系数据库映射,后者将对象模型映射到关系数据库表。我们认为每个DCPS主题都类似于关系数据库表,每个样本都作为该表中的一行。DDS规范具有从DCPS到DLRL的默认映射。或者,开发人员可以选择通过XML映射文件指定自己的自定义映射。

OpenDDS当前未实现DLRL。

目录

OpenDDS股票报价器示例

我们的示例说明了通过DDS DCPS层发布和订阅数据样本。该示例包含两个DCPS主题,都与股市有关。

股票报价发布者将股票报价样本发布给感兴趣的订阅者;每个报价均包含证券的股票代码,其价值和时间戳。报价在整个交易日中定期发布,因为买卖交易会影响证券的基础价值。另外,证券交易所事件发布者发布与证券交易所有关的重要事件,即,何时交易所开放,关闭,何时暂停交易或恢复交易。

我们的订户同时订阅股票报价和股票交易所事件。订户打印其所看到的每个报价的代码符号和值。当订阅者收到表明当天股票交易所已经关闭的事件时,它将正常关闭。因此,“封闭”证券交易所事件的接收是订户停止预期股票报价样本的信号。

我们将演示如何使用相同的发布者和订阅者代码通过TCP和UDP传输进行通信。传输配置隔离在一组配置文件中,使我们无需更改任何代码即可切换传输。

目录

IDL类型

首先,我们在IDL中定义已发布的DDS数据类型:

#include "orbsvcs/TimeBase.idl"
module StockQuoter
{
   
#pragma DCPS_DATA_TYPE "StockQuoter::Quote"
#pragma DCPS_DATA_KEY "StockQuoter::Quote ticker"
  struct Quote {
   
    string ticker;
    string exchange;
    string full_name;
    double value;
    TimeBase::TimeT timestamp;
  };

#pragma DCPS_DATA_TYPE "StockQuoter::ExchangeEvent"
#pragma DCPS_DATA_KEY "StockQuoter::ExchangeEvent exchange"

  enum ExchangeEventType {
    TRADING_OPENED,
                           TRADING_CLOSED,
                           TRADING_SUSPENDED,
                           TRADING_RESUMED };
  struct ExchangeEvent {
   
    string exchange;
    ExchangeEventType event;
    TimeBase::TimeT timestamp;
  };
};

我们发布两种数据类型:每个股票报价的报价类型,以及用于指示何时打开,关闭证券交易所以及何时暂停或恢复交易的ExchangeEvent类型。该DCPS_DATA_TYPE编译标记的类型与DDS使用。的 DCPS_DATA_KEY每种类型的定义是针对每个唯一标识符 的实例中的数据类型的。我们报价类型的关键是股票的股票代码。一整天,我们希望为每个股票代号发布许多值或样本。每个股票代号的已发布样本集属于同一实例。在我们的示例中,我们将发布两个股票代号,并因此发布两个实例:SPY(标准普尔存托凭证,即S&P 500)和MDY(S&P中盘存托凭证,即S&P中盘400)。

接下来,我们使用OpenDDS的opendds_idl编译器编译IDL 以生成 类型支持代码。类型支持代码包括生成的DCPS 数据写入器和数据读取器 C ++类以及其他IDL代码。DDS使用类型安全的接口进行发布和订阅。类型安全的接口具有几个优点:首先,在编译时更容易捕获编程错误;第二,当在编译时已知封送数据类型时,可以使生成的封送代码非常高效。第三,我们可以避免any在数据传输中使用低效类型,例如CORBA 。

生成股票报价器的IDL类型的类型支持代码的命令如下:

$ DDS_ROOT / bin / opendds_idl StockQuoter.idl

此命令生成以下文件:

StockQuoterTypeSupport.idl
StockQuoterTypeSupportImpl.h
StockQuoterTypeSupportImpl.cpp

但是,我们不需要opendds_idl手动运行编译器。稍后,我们将使用Make Project Creator(MPC)项目为我们自动化构建步骤。

接下来,我们使用TAO的IDL编译器来编译所有三个IDL文件- StockQuoter.idl我们手动编写的 文件,以及由生成的类型支持文件opendds_idl

tao_idl -I $ DDS_ROOT -I $ TAO_ROOT / orbsvcs StockQuoter.idl
tao_idl -I $ DDS_ROOT -I $ TAO_ROOT / orbsvcs StockQuoterTypeSupport.idl

目录

发行人

接下来,我们编写一个发布者,以通过DDS发布股票报价和股票交易所事件。首先,我们包括由opendds_idl编译器生成的两个类型支持头文件。

#include "StockQuoterTypeSupportImpl.h"

我们还包括DCPS发布者,服务参与者和QoS标头文件。

#include "dds/DCPS/Service_Participant.h"
#include "dds/DCPS/Marked_Default_Qos.h"
#include "dds/DCPS/PublisherImpl.h"
#include "ace/streams.h"
#include "orbsvcs/Time_Utilities.h"

以下常量用于我们的域,类型名称和主题名称。每种类型均在单独的主题上发布。订户必须为其域,类型名称和主题名称使用相同的值。

// constants for Stock Quoter domain Id, types, and topic
DDS::DomainId_t QUOTER_DOMAIN_ID = 1066;
const char* QUOTER_QUOTE_TYPE = "Quote Type";
const char* QUOTER_QUOTE_TOPIC = "Stock Quotes";
const char* QUOTER_EXCHANGE_EVENT_TYPE = "Exchange Event Type";
const char* QUOTER_EXCHANGE_EVENT_TOPIC = "Stock Exchange Events";

在发布证券交易所事件(即打开,关闭,暂停或恢复)时,我们还将发布该事件适用的证券交易所的名称。

const char* STOCK_EXCHANGE_NAME = "Test Stock Exchange";

这是获取当前日期和时间的简单辅助方法。

TimeBase::TimeT get_timestamp()
{
   
  TimeBase::TimeT retval;
  ACE_hrtime_t t = ACE_OS::gethrtime ();
  ORBSVCS_Time::hrtime_to_TimeT (retval, t);
  return retval;
}

发布者的源代码文件的其余部分包含main()。我们输入发布者的main()

int main (int argc, char *argv[])
{
   
  DDS::DomainParticipantFactory_var dpf =
    DDS::DomainParticipantFactory::_nil();

  DDS::DomainParticipant_var participant =
    DDS::DomainParticipant::_nil();

  try
  {
   

首先,我们创建一个域参与者。DDS发布者可以在多个独立域上发布,但是我们的示例仅在一个域上发布。我们使用TheDomainParticipantFactoryWithArgs宏将命令行参数传递到DCPS中,并获得单例域参与者工厂。我们使用域参与者的默认服务质量策略为“ Quote”域创建一个域参与者。QUOTER_DOMAIN_ID传递给工厂的值在发布者和订阅者中必须相同。

// Initialize, and create a DomainParticipant

dpf = TheParticipantFactoryWithArgs(argc, argv);

participant = dpf->create_participant(
QUOTER_DOMAIN_ID,
PARTICIPANT_QOS_DEFAULT,
DDS::DomainParticipantListener::_nil());

if (CORBA::is_nil (participant.in ()))
{
cerr << “create_participant failed.” << endl;
ACE_OS::exit(1);
}

然后,我们通过域参与者使用默认的服务质量值创建发布者。PublisherListener 当某些与发布相关的事件发生时,我们可以附加一个DCPS调用的。但是,我们不在乎那些事件,因此我们附加了一个nil侦听器。

  // Create a publisher for the two topics
    // (PUBLISHER_QOS_DEFAULT is defined in
    // Marked_Default_Qos.h)
    DDS::Publisher_var pub =
      participant->create_publisher(
        PUBLISHER_QOS_DEFAULT,
        DDS::PublisherListener::_nil());

    if (CORBA::is_nil (pub.in ()))
    {
   
      cerr << "create_publisher failed." << endl;
      ACE_OS::exit(1);
    }

通过DCPS进行发布涉及三个步骤。首先,我们为发布的数据样本注册每种类型。我们的示例发布了两种IDL类型的示例Quote和ExchangeEvent。其次,我们创建一个或多个发布主题。每个主题只能绑定一种类型。因此,我们为两种类型的每种类型创建一个主题。第三,我们为每个主题创建一个数据编写器,并通过该数据编写器发布示例。

我们首先向域参与者注册IDL Quote类型,并为Quote类型传递生成的QuoteTypeSupportImpl类的实例。我们用于报价类型的名称(存储在常量值中QUOTER_QUOTE_TYPE)必须与订阅服务器上使用的名称匹配。创建主题时,我们指定此类型名称,从而使DCPS能够在以后为该主题创建适当类型的数据写入器。

 // Register the Quote type
    StockQuoter::QuoteTypeSupport_var quote_servant
      = new StockQuoter::QuoteTypeSupportImpl();

    if (DDS::RETCODE_OK !=
          quote_servant->register_type(participant.in (),
                                       QUOTER_QUOTE_TYPE))
             {
   
      cerr << "register_type for " << QUOTER_QUOTE_TYPE
           << " failed." << endl;
      ACE_OS::exit(1);
    }

然后,我们使用生成的ExchangeEventTypeSupportImpl类以相同的方式向域参与者注册IDL ExchangeEvent类型。我们的DCPS域参与者可以发布有关Quote或ExchangeEvent类型的主题。

 // Register the ExchangeEvent type
    StockQuoter::ExchangeEventTypeSupport_var exchange_evt_servant
      = new StockQuoter::ExchangeEventTypeSupportImpl();

    if (DDS::RETCODE_OK !=
          exchange_evt_servant->register_type
  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值