OpenDDS系列(4) —— IDL 简要介绍


IDL

OpenDDS(DDS)主要的目的是用于在网络上交换数据,但究竟什么是数据?

DDS中,可以被交换的数据是sturct(结构体)。例如我们可以创建一个包含特定领域的结构体,比如:

struct MyData {
  long counter;
  string message;
  double threshold;
};

这个结构描述了一段可以通过dds发送和接收的数据,换句话说,就是topic(主题)。

我们必须考虑opendds能够在用不同语言创建的进程之间交换数据。例如,C++ Publisher发送一个主题,它可以被 Java 进行接收。基于这个原因,我们必须定义交换C++和Java数据的结构。为了避免这个问题,使用.idl文件在一个单独的文件中定义主题文件格式。当我们完成创建它时,可以从这个文件创建Java和C ++中的所有必需的源文件。我们以不可知的格式定义主题,然后使用一些OpenDDS工具创建我们需要的C ++或Java文件。有了这个,我们可以仅创建一次主题,以避免错误,因为数据仅在同一个地方被定义了一次。换句话说,当我们决定创建一些要交换的主题时,我们需要:

  • 定义主题的字段
  • 在.idl文件中定义主题
  • 编译用于生成C ++文件的.idl文件
  • 编译用于生成Java文件的.idl文件

当然,如果我们只使用一种语言,我们不需要为其他语言创建文件。

4.1 IDL

我们需要定义我们想要在 IDL 中交换的结构。这是一个用C ++风格编写的定义结构化文件的文件。

IDL(接口描述语言)是一种使用C ++风格定义结构的文本文件。该文件包含必须交换的数据结构。结构由struct关键字定义。以下是一个包含真实值和字符串的结构示例:

struct SomeUsefulStruct {
  double myPreciousDouble;
  string veryVeryImportantString;
};

正如我们所看到的,创建一个字符串并不困难。在下表中,我们将显示可以在字符串内使用的所有数据类型:

常见的IDL数据类型

TypeDescriptionC++ equivalent
BooleanA true/false valuebool
charSimple char valuechar
wcahrWide char valuewchar_t
stringA string with variable lengthstring
wstringA string with variable length with wide char characterswstring
octetA byte
shortShort integer valueshort
unsigned shortUnsigned short integer valueunsigned short
long32 bit integer valueint
unsigned longUnsigned 32 bit integer valueunsigned int
long long64 bit integer valuelong long
unsigned long longUnsigned 64 bit integer valueunsigned long long
floatFloat valuefloat
doubleDouble valuedouble
fixedBig valueNot supported at the moment

作为一个例子,我们可以尝试创建一个用于检查数据的IDL消息。创建一个test.idl文件,并复制以下内容:

module Sample {
    struct DataTypesList 
    {
      boolean               booleanValue;
      char                  charValue;
      wchar                 wcharValue;
      string                stringValue;
      wstring               wstringValue;
      octet                 octedValue;
      short                 shortValue;
      unsigned short        unsignedShortValue;
      long                  longValue;
      unsigned long         unsignedLongValue;
      long long             longLongValue;
      unsigned long long    unsignedLongLongValue;
      float                 floatValue;
      double                doubleValue;
      fixed                 fixedValue;
    };
}; // module Sample

将其保存,并使用IDL命令build。

opendds_idl.exe .\file.idl -o .
tao_idl.exe -Sg file.idl
tao_idl.exe -Sg fileTypeSupport.idl -o .

编译之后得到一堆文件,打开fileC.h 我们可以发现C++结构。

struct  DataTypesList
{
  // TAO_IDL - Generated from
  // be\be_type.cpp:307
  typedef                   DataTypesList_var _var_type;
  typedef                   DataTypesList_out _out_type;
  static void               _tao_any_destructor (void *);
  ::CORBA::Boolean          booleanValue;
  ::CORBA::Char             charValue;
  ::CORBA::WChar            wcharValue;
  ::TAO::String_Manager     stringValue;
  ::TAO::WString_Manager    wstringValue;
  ::CORBA::Octet            octedValue;
  ::CORBA::Short            shortValue;
  ::CORBA::UShort           unsignedShortValue;
  ::CORBA::Long             longValue;
  ::CORBA::ULong            unsignedLongValue;
  ::CORBA::LongLong         longLongValue;
  ::CORBA::ULongLong        unsignedLongLongValue;
  ::CORBA::Float            floatValue;
  ::CORBA::Double           doubleValue;
};

正如所看到的,idl编译器转换自定义c ++类型中的idl数据类型,允许执行某种抽象。其使用常见的数据类型映射到C++中。

4.2 示例

我们想要构建一个场景模拟器。模拟器由两个过程组成:

  • Gui:这是模拟器地图,用户可以在该模拟器地图中与球员等进行交互
  • Core:这是模拟器的核心,执行微积分并具有程序逻辑的部分

这是两个独立的过程,它们之间会发生交互。

我们需要创建一个包含idl,其中包含了我们想要交换的消息。消息的类型取决于我们想要执行的操作。

该示例中用户可以从场景中添加和删除玩家。对于这个用例,Gui必须能够发送添加玩家的命令和删除玩家的命令。而且,一旦玩家被创建,GUI必须读取玩家的位置以便将其显示在正确的位置。另一方面,Core必须接收添加/删除玩家的命令,并向操作结果发送回复给Gui,然后定期发送玩家的位置。

如下是这个示例的示意图:

Sequence diagram for add/remove a player from the simulation.

模拟添加/删除玩家的流程图

从用例中可以看到需要以下消息:

  • AddPlayer:这是包含关于必须创建的玩家的数据的消息,如名称,简介及其初始位置
  • PlayerAdded:这是包含有关添加到场景中的球员数据的答复。它包含所有以前的数据和另一个称为result的字段,表示是否成功添加了玩家
  • RemovePlayer:这条消息包含了必须被移除的玩家的信息。我们需要在其中指定玩家名称(假设在一个场景中玩家名称是唯一的)
  • PlayerRemoved:这条消息包含了删除玩家的操作结果:它包含已删除玩家的数据,并且还包含一个表示操作是否成功的标志
  • PlayerPosition:此消息包含一个球员的位置。它包含玩家的名字及位置

我们需要创建一个包含这些消息的idl

#ifndef SIMULATION_IDL_
#define SIMULATION_IDL_

module Message {
    #pragma DCPS_DATA_TYPE "Message::LLA"
    struct LLA {
      double latitude;
      double longitude;
      double altitude;
    };

    #pragma DCPS_DATA_TYPE "Message::Orientation"
    struct Orientation {
      double roll;
      double pitch;
      double yaw;
    };

    #pragma DCPS_DATA_TYPE"Message::PlayerPosition"
    // Position of a player that is presentinside a scenario.
    struct PlayerPosition {
        string      name;
        LLA         pos;
        Orientation ori;
    };

    #pragma DCPS_DATA_TYPE "Message::AddPlayer"
    // Command for adding a player to thescenario.*
    struct AddPlayer {
        string      name;
        string      profile;
        LLA         pos;
        Orientation ori;
    };

    #pragma DCPS_DATA_TYPE "Message::RemovePlayer"
    // Command for removing a player from thescenario.*
    struct RemovePlayer {
      string name;
    };

    #pragma DCPS_DATA_TYPE "Message::PlayerAdded"
    // Response that says if a player is addedto the scenario.*
    struct PlayerAdded {
        string      name;
        string      profile;
        LLA         pos;
        Orientation ori;
        boolean     result;
    };
    #pragma DCPS_DATA_TYPE "Message::PlayerRemoved"

    // Response that says if a player isremoved from the scenario.*
    struct PlayerRemoved {
      string  name;
      boolean result;
    };
}; // module Message

#endif // !SIMULATION_IDL_

该代码显示了一些基本结构和一些组件(例如选手的位置)。

此时,我们可以构建IDL以获取所需的C++文件,因此将IDL保存在一个文件中,例如sample.idl, 且给出了如下的命令:

opendds_idl.exe sample.idl -o .
tao_idl.exe -Sg sample.idl -o .
tao_idl.exe -Sg sampleTypeSupport.idl -o .

此处创建了一堆文件,可以将其包含到项目中。以下是这些生成的代码分析:

  • sampleC.h / sampleC.cpp:这是文件定义了用C++创建的结构体。每个结构体都包含在idl文件中定义的所有成员。它们还包含用户和发布者中使用的一些typedef,以及一些重载的流操作符

  • sampleC.inl:目前它不包含任何内容,仅包含评论

  • sampleS.h / sampleS.cpp:这些文件包含发布者和订阅者所需的一些特征。它们用于主题注册
  • sampleTypeSupportC.h /sampleTypeSupportC.cpp / sampleTypeSupportC.inc / sampleTypeSupportC.inl:在这种情况下,这些文件只包含一些OpenDDS头文件,当我们需要在代码中实现主题时可以使用这些头文件
  • sampleTypeSupportImpl.h / sampleTypeSupportImpl.cpp:这些文件定义了当需要通过网络发送/接收结构时序列化结构的流操作符
  • sampleTypeSupportS.h /sampleTypeSupportS.cpp:这些文件包含编译代码中结构所需的头文件。没有特别的

需要注意的一点是:在.idl文件中,我们将消息创建为一个module; 特别是在消息模块中。这在我们的C++文件中被翻译成命名空间。所以我们在Message模块中创建了IDL中的结构,而在C++文件中,这些结构进入了Message名称空间。这非常有用,特别是当我们想要组织大量的主题时,我们希望避免在代码中与其他类名称冲突。

4.3 如何使用

这些文件是IDL描述文件的C++翻译。为了使用它们,需要将其包含进我们的工程中,然后就可以利用OpenDDS的API收发数据。

4.4 总结

本文介绍了如何创建一个基本的IDL,且简要分析了通过编译创建的源代码。

  • 12
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值