我正在尝试创建最简单的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)中运行和发布。你知道我的代码可能出了什么问题吗?
顺便说一下。我使用RTI Connext 5.0实现DDS。
致敬约翰
发布于 2013-03-08 23:51:32
使用RTI Connext,TopicBuiltinTopic的行为并不像人们所期望的那样。查看C# API DDS::TopicBuiltinTopicData Class Reference的文档
注意:
DDS_TopicBuiltinTopicData内置主题旨在传达有关发现的主题的信息。本主题的样本不会在网络上以单独的数据包进行传播。相反,数据作为其他内置主题(DDS::PublicationBuiltinTopicData和DDS::SubscriptionBuiltinTopicData)携带的信息的一部分发送。因此,TopicBuiltinTopicDataDataReaders将不会接收任何数据。
它的基本意思是:由于在Connext中实现发现的方式,您将不会在任何TopicBuiltinTopicData DataReaders中看到任何数据。这就是您在代码片段中观察到的内容。
幸运的是,仍然可以在公交车上获得有关主题的信息。这必须通过PublicationBuiltinTopicData和SubscriptionBuiltinTopicData实现。如果查看C# API DDS::PublicationBuiltinTopicData Class Reference的文档,就会发现数据包含字符串字段topic_name和type_name。此外,您还可以获得有关类型结构的信息,但这是更高级和特定于实现的信息。
三个备注,以防您计划实现对内建主题的发布和订阅的阅读。首先,最好引用相应的TypeSupport属性,而不是像"DCPSTopic"那样硬编码内置主题的名称,如下所示:
reader = sub.lookup_datareader(
DDS.PublicationBuiltinTopicDataTypeSupport.PUBLICATION_TOPIC_NAME);那么很高兴知道,使用Connext时,内置DataReaders将不会包含有关与内置订阅服务器位于同一DomainParticipant中的发布或订阅的任何示例。换句话说,您只能看到其他参与者的实体,而不能看到您自己的实体。
最后,在使用您的代码时,我注意到,除非我按如下所示替换序列的构造函数调用,否则无法读取示例:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();代替
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);数据序列也是类似的。我不知道这是为什么,但它应该不会有任何实际影响。
发布于 2013-03-11 22:16:43
雷尼尔是对的。Connext DDS不直接在TopicBuiltinTopicData中传播主题;相反,它在PublicationBuitinTopicData和SubscriptionBuiltinTopicData中间接传播主题。这是DDS规范所允许的。
在这篇标题为Detect the presence of DomainParticipants, DataWriters and DataReaders in the DDS Domain的操作指南中有关于如何使用内置主题的信息。HOWTO包含了一些可用的示例代码。它是用Java而不是C#编写的,但是它应该很容易映射。这里的示例一次读取一个样本,因此您不需要处理序列sytax。
您必须使用的原因:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq();而不是:
DDS.SampleInfoSeq infoSeq = new DDS.SampleInfoSeq(10);读/取API具有两种不同的行为,这取决于传递的序列是“空的”(即具有零分配/最大长度)还是具有分配的长度。
如果序列是空的,那么read/take的行为就像零拷贝API,这意味着序列中的实际元素是从已经存储在中间件中的元素中“借出”出来的。由于这个原因,必须传入的序列必须是“空”序列,以便中间件知道可以用对内部元素的引用替换内容。在访问元素之后,您必须将“借出的元素”返回到调用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++的操作文档中找到有关如何使用DDS序列的更多信息。它是用C++示例编写的,但这些原则适用于所有语言。
你好,杰拉多
https://stackoverflow.com/questions/15295220
复制相似问题