订阅DDS中的内置主题“DCPSTopic”

时间:2013-03-08 13:36:52

标签: c# data-distribution-service

我正在尝试创建最简单的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实现。

此致 约翰

2 个答案:

答案 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_nametype_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)

雷尼尔是对的。 Connext DDS不直接在TopicBuiltinTopicData中传播主题;相反,它间接地在PublicationBuitinTopicDataSubscriptionBuiltinTopicData中进行。这是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 ++示例编写的,但原则适用于所有语言。

此致 赫拉尔