2.1 使用DCPS
本章重点介绍一个示例应用程序, 使用 DCPS 将数据从单个发布程序到单个订阅服务器进程。它是基于一个简单的信息应用,单个发布者发布信息,单个订阅者订阅消息的应用程序, 单个订阅服务器订阅给他们。我们使用默认的 qos 属性和默认的 tcp/ip 传输。此示例所有源代码可以在$DDS_ROOT/DevGuideExamples/DCPS/Messenger/ 目录下。额外的 DDS 和 DCPS功能在后面的章节中讨论。
2.1.1 定义数据类型
DDS使用的每个数据类型都是使用 idl 定义的。OpenDDS 使用 #pragma指令来确定 dds 传输和处理的数据类型。这些数据类型由TAO IDL编译器和 OpenDDS IDL编译器生成必要的代码来使用 OpenDDS 传输这些类型的数据。下面是定义我们的消息的 idl 文件数据类型:
module Messenger {
#pragma DCPS_DATA_TYPE "Messenger::Message"
#pragma DCPS_DATA_KEY "Messenger::Message subject_id"
struct Message {
string from;
string subject;
long subject_id;
string text;
long count;
};
};
DCPS_DATA_TYPE 杂注标记用于 OpenDDS 的数据类型。完全作用域的类型名称必须与此杂注一起使用。OpenDDS 要求数据类型为结构。该结构可能包含标量类型 (短、长、浮点等)、枚举、字符串序列、数组、结构和联合。本示例定义的结构Message在 OpenDDS 示例中使用的 messenger 模块。
DCPS_DATA_KEY 杂注标识了 DCPS 数据类型的字段, 用作此类型键(key)。数据类型可能有零个或多个键。这些键用于标识不同的主题中的实例。每个键都应是数字或枚举类型、字符串或这些类型之一的 typedef. 1杂注被传递的完全作用域类型和成员标识该类型的键的名称。多个键用分别的DCPS_DATA_KEY 杂住。在上面的例子中, 我们确定了 Messenger::Message的subject_id 成员作为一个键。每个以唯一的 subject_id 值发布的示例都将定义为属于同一主题中的不同实例。由于我们使用默认 qos 策略, 具有相同 subject_id 值的后续示例被视为该实例的替换值。(最后一句话是什么意思呢,主要怎么用,还不是很明白)
2.1.2 处理IDL
OpenDDS IDL首先由 TAO IDL 编译器处理。
tao_idl Messenger.idl
此外, 我们需要用 OpenDDS idl 编译器处理 idl 文件, 以生成OpenDDS 需要marshal和 demarshal 的Message的序列化和键支持代码,以及数据读取者和写入者的类型支持代码。此 idl编译器位于 $ DDS_ROOT/bin/ 并为每个被处理的 idl 文件生成三文件。三文件都以原始的 idl 文件名开头, 并显示为如下
- TypeSupport.idl
- TypeSupportImpl.h
- TypeSupportImpl.cpp
例如, 运行 opendds_idl 如下
opendds_idl Messenger.idl
生成 MessengerTypeSupport. idl、MessengerTypeSupportImpl 和MessengerTypeSupportImpl.cpp. idl 文件,IDL文件包含 MessageTypeSupport,MessageDataWriter 和 MessageDataReader 接口定义。这些类型特定我们以后使用的 dds 接口在域中注册我们的数据类型, 发布示例的数据类型, 并接收已发布的示例。实现文件包含这些接口的实现。生成的 idl 文件本身应该用
用于生成存根和骨架的道 idl 编译器。这些和实现文件应与使用Message类型的 OpenDDS 应用程序链接。opendds idl 编译器有许多专门用于生成的代码的选项。这些选项在第8章所述。
通常, 您不直接调用TAO或 OpenDDS idl 编译器如上所述, 但让您的构建环境是为您做的。使用 mpc 时, 整个过程被简化,从 dcpsexe_with_tcp 项目继承。这里是共同的 mpc 文件部分发布服务器和订阅服务器
project(*idl): dcps {
// This project ensures the common components get built first.
TypeSupport_Files {
Messenger.idl
}
custom_only = 1
}
DCPS 父项目添加支持自定义生成规则的类型。typesupport_files部分告诉 mpc 从信使生成Message类型支持文件从Messager.idl
使用 OpenDDS idl 编译。以下是发布者部分:
project(*Publisher): dcpsexe_with_tcp {
exename = publisher
after += *idl
TypeSupport_Files {
Messenger.idl
}
Source_Files {
Publisher.cpp
}
}
dcpsexe_with_tcp项目链接DCPS库。
为完整起见, 这里是 mpc 文件的订阅部分:
project(*Subscriber): dcpsexe_with_tcp {
exename = subscriber
after += *idl
TypeSupport_Files {
Messenger.idl
}
Source_Files {
Subscriber.cpp
DataReaderListenerImpl.cpp
}
}
2.1.3 一个简单的Message发布者
在本节中, 我们将介绍设置简单 OpenDDS 发布者所涉及的步骤过程.该代码分为逻辑部分, 并解释为我们提出的每一节。
我们省略了代码中一些无趣的部分 (如 # 包含指令, 错误处理和进程同步)。此示例发布服务器的完整源代码中的 Publisher.cpp 和 Writer.cpp 文件中找到$DDS_ROOT/DevGuideExamples/DCPS/Messenger/.
2.1.3.1 初始化参与者
main () 的第一部分将当前进程初始化为 OpenDDS 参与者
int main (int argc, char *argv[]) {
try {
DDS::DomainParticipantFactory_var dpf =
TheParticipantFactoryWithArgs(argc, argv);
DDS::DomainParticipant_var participant =
dpf->create_participant(42, // domain ID
PARTICIPANT_QOS_DEFAULT,
0, // No listener required
OpenDDS::DCPS::DEFAULT_STATUS_MASK);
if (!participant) {
std::cerr << "create_participant failed." << std::endl;
return 1;
}
TheParticipantFactoryWithArgs 宏在 Service_Participant.h中定义。并使用命令行参数初始化域参与者工厂。这些命令行参数用于初始化 OpenDDS 服务使用的 orb以及服务本身。这允许我们在命令行上传递 ORB_init () 选项以及形如 -DCPS*的OpenDDS 配置选项。可用的 OpenDDS 选项在7章中作了详细说明。
create_participant () 操作使用域参与者工厂注册此进程作为由 id 42 指定的域中的参与者。参与者使用默认 qos 策略, 没有侦听器。使用 OpenDDS 默认状态掩码可确保所有相关的通信状态变化 (例如, 数据可用, 活泼丢失) 在中间件被传递到应用程序 (例如, 通过侦听器上的回调)。
用户可以使用范围内的 id 定义任意数量的域 (0x0 ~ 0x7fffffff)。所有其他值由实现保留供内部使用。
返回的域参与者对象引用然后用于注册我们的消息数据类型.