我正在尝试创建最简单的C#应用程序,这将允许我获取所选DDS域中当前可用的主题。但我似乎无法使其发挥作用。
// Create the DDS Domain participant on domain ID 0
DDS.DomainParticipant participant =
DDS.DomainParticipantFactory.get_instance().create_participant(
0,
DDS.DomainParticipantFactory.PARTICIPANT_QOS_DEFAULT,
null, /* Listener */
DDS.StatusMask.STATUS_MASK_NONE);
DDS.Subscriber sub = participant.get_builtin_subscriber();
DDS.DataReader reader1 = sub.lookup_datareader("DCPSTopic");
DDS.TopicBuiltinTopicDataDataReader builtinReader1 =
(DDS.TopicBuiltinTopicDataDataReader)reader1;
DDS.TopicBuiltinTopicDataSeq topicSeq = new DDS.TopicBuiltinTopicDataSeq(10) ;
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
builtinReader1.read(topicSeq,
infoSeq,
10,
DDS.SampleStateKind.ANY_SAMPLE_STATE,
DDS.ViewStateKind.ANY_VIEW_STATE,
DDS.InstanceStateKind.ANY_INSTANCE_STATE);
当运行上面的代码时,我在最后一行(builtinReader1.read(...))中得到“Retcode_NoData”异常,即使发布者和订阅者都在同一个域(域0)中运行和发布。你对我的代码有什么问题有任何想法吗?
顺便说一下。我使用DDS的RTI Connext 5.0实现。此致 约翰
答案 0 :(得分:1)
使用RTI Connext时,TopicBuiltinTopic
的行为并不像人们预期的那样。查看C# API DDS::TopicBuiltinTopicData Class Reference的文档:
注意:
DDS_TopicBuiltinTopicData
内置主题旨在传达 有关已发现主题的信息这个主题的样本不是 在线上的单独数据包中传播。而是发送数据 作为其他内置主题所载信息的一部分 (DDS::PublicationBuiltinTopicData
和DDS::SubscriptionBuiltinTopicData
)。因此TopicBuiltinTopicData
DataReaders不会收到任何数据。
基本上说的是:由于在Connext中实现发现的方式,您不会在任何TopicBuiltinTopicData
DataReader中看到任何数据。这是您在代码段中观察到的内容。
幸运的是,仍然可以在总线上获取有关主题的信息。这必须通过PublicationBuiltinTopicData和SubscriptionBuiltinTopicData进行。如果您查看C# API DDS::PublicationBuiltinTopicData Class Reference的文档,可以看到数据包含字符串字段topic_name
和type_name
。此外,您可以获取有关类型结构的信息,但这是更高级和特定于实现的。
如果您计划实施“发布和订阅内置主题”的阅读,请注意三点。首先,与使用"DCPSTopic"
一样,不是硬编码内置主题的名称,最好引用相应的TypeSupport属性,如:
reader = sub.lookup_datareader(
DDS.PublicationBuiltinTopicDataTypeSupport.PUBLICATION_TOPIC_NAME);
然后,很高兴知道使用Connext,内置DataReader将不包含与内置订阅服务器位于同一DomainParticipant中的出版物或订阅的任何示例。换句话说,您只能看到其他参与者的实体,但不能看到您自己的实体。
最后,在玩你的代码时,我注意到除非我按如下方式替换序列的构造函数调用,否则读取样本不起作用:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();
代替
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
和数据序列类似。我不知道为什么会这样,但它不应该有任何实际意义。
答案 1 :(得分:1)
TopicBuiltinTopicData
中传播主题;相反,它间接地在PublicationBuitinTopicData
和SubscriptionBuiltinTopicData
中进行。这是DDS规范允许的。
有关如何使用本HOWTO标题为Detect the presence of DomainParticipants, DataWriters and DataReaders in the DDS Domain的内置主题的信息。 HOWTO包含一些工作示例代码。它是用Java而不是C#,但应该很容易映射。这个示例一次读取一个Sample,因此您不需要处理序列sytax。
您必须使用的原因:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();
而不是:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
读取/获取API是否具有两种不同的行为,具体取决于传递的序列是“空”(即具有零分配/最大长度)还是具有分配的长度。
如果序列为空,这是你使用默认构造函数得到的,那么read / take表现为零拷贝API。这意味着序列中的实际元素从已存储在中间件内的元素中“借出”。由于这个原因,必须传入的序列必须是一个“空”序列,以便中间件知道可以用对内部元素的引用替换内容。访问元素后,必须将“loaned elements”返回给调用DataReader::return_loan
操作的中间件。
如果序列不为空。然后DDS将假设元素已预先分配,并将尝试将数据复制到您传递的元素中。您展示的代码的问题是
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);
仅分配序列本身。但不是元素。因此,当尝试进行复制时,读取/接听调用将失败。如果您想使用这个非零拷贝API,您必须使用每个元素的分配/分配来跟随调用,即:
for (int i=0; i< 10; i++ ) {
infoSeq.set_at(i, new DDS.SampleInfo());
}
同样适用于数据序列。
如果这样做,则不必使用DataReader::return_loan
操作。但是会有额外的副本,所以效率会降低。
您可以在本标题为Howto use OMG DDS Sequences in C++的HOWTO中找到有关如何使用DDS序列的更多信息。它是用C ++示例编写的,但原则适用于所有语言。
此致 赫拉尔