记OpenDDS订阅内置主题的一些坑

2023-10-24 02:32
文章标签 内置 订阅 主题 opendds

本文主要是介绍记OpenDDS订阅内置主题的一些坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

由于某个需求,现在需要订阅OpenDDS的内置主题,首先我们通过官方文档来看下OpenDDS有哪些内置主题:

一共四个,分别对应参与者、主题、生产者、订阅者,这次我们要订阅的是Topic的信息,但是这里没有说明该怎么订阅,也没说明这四个主题的消息格式是怎样的,不要急,往下翻一下第六章就能看到:

我们可以看到,DCPSTopic这个主题的消息类型为TopicBuiltinTopicData,本章最后一小节给出的是DCPSParticipant主题的C++示例代码,那么我们仿照着写出DCPSTopic的Java代码:

        DomainParticipantFactory dpf = TheParticipantFactory.WithArgs(new StringSeqHolder(args));if (dpf == null) {return;}DomainParticipant dp = dpf.create_participant(4, PARTICIPANT_QOS_DEFAULT.get(), null, DEFAULT_STATUS_MASK.value);if (dp == null) {return;}// 订阅内置主题DCPSTopicSubscriber subscriber = dp.get_builtin_subscriber();DataReader dr = subscriber.lookup_datareader("DCPSTopic");TopicBuiltinTopicDataDataReader pdr = TopicBuiltinTopicDataDataReaderHelper.narrow(dr);TopicBuiltinTopicDataSeqHolder partData  = null;SampleInfoSeqHolder infos                = null;int ret = pdr.read(partData, infos, 20, ANY_SAMPLE_STATE.value, ANY_VIEW_STATE.value, ANY_INSTANCE_STATE.value);if (ret == RETCODE_OK.value) {TopicBuiltinTopicData[] datas =  partData.value;for (TopicBuiltinTopicData data : datas) {String topicName = data.name;// do-something}}

需要注意,这四个主题,各有对应的DataReader、DataSeqHolder,绝不能混用

结果运行后报错,提示:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x000000006f4af755, pid=11244, tid=0x00000000000015e4
#

JVM出现了错误,于是我们看错误日志hs_err_pidXXXX.log,有如下内容:

Stack: [0x00000000031a0000,0x00000000032a0000],  sp=0x000000000329e990,  free space=1018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0x13f755]
C  [idl2jni_runtimed.dll+0x1ed69]  JNIEnv_::GetObjectClass+0x59
C  [idl2jni_runtimed.dll+0x21ad3]  deholderize<_jobjectArray *>+0x53
C  [OpenDDS_DCPS_Javad.dll+0x113b2b]  Java_DDS__1TopicBuiltinTopicDataDataReaderTAOPeer_read+0xab
C  0x00000000035a8c67Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  DDS._TopicBuiltinTopicDataDataReaderTAOPeer.read(LDDS/TopicBuiltinTopicDataSeqHolder;LDDS/SampleInfoSeqHolder;IIII)I+0
j  hnu.yhc.ddsclient.dds.DdsSubscriber.<init>(Lhnu/yhc/ddsclient/dds/DataReaderListenerBaseEx;)V+119
j  hnu.yhc.ddsclient.BuiltInTest.main([Ljava/lang/String;)V+11
v  ~StubRoutines::call_stub

很显然是在_TopicBuiltinTopicDataDataReaderTAOPeer.read这个方法出现错误,并且异常来源于JNI调用的C++代码中的JNIEnv_::GetObjectClass处,通过观察Java_DDS__1TopicBuiltinTopicDataDataReaderTAOPeer_read方法的代码,基本可以找到问题:TopicBuiltinTopicDataSeqHolder和SampleInfoSeqHolder没有初始化导致的!

于是我们将其使用空构造方法初始化,再次运行后,还是出错!这次异常栈信息如下:

Stack: [0x00000000026c0000,0x00000000027c0000],  sp=0x00000000027be800,  free space=1018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0x146099]
C  [OpenDDS_DCPS_Javad.dll+0x9b7f9]  JNIEnv_::GetArrayLength+0x59
C  [OpenDDS_DCPS_Javad.dll+0xcd33b]  copyToCxx+0x5b
C  [OpenDDS_DCPS_Javad.dll+0x113b6c]  Java_DDS__1TopicBuiltinTopicDataDataReaderTAOPeer_read+0xec
C  0x0000000002ac8c67Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j  DDS._TopicBuiltinTopicDataDataReaderTAOPeer.read(LDDS/TopicBuiltinTopicDataSeqHolder;LDDS/SampleInfoSeqHolder;IIII)I+0
j  hnu.yhc.ddsclient.dds.DdsSubscriber.<init>(Lhnu/yhc/ddsclient/dds/DataReaderListenerBaseEx;)V+131
j  hnu.yhc.ddsclient.BuiltInTest.main([Ljava/lang/String;)V+11
v  ~StubRoutines::call_stub

错误出现在copyToCxx方法调用GetArrayLength处,我们看一下这两个Holder的定义,果不其然内部都包含一个数组,且空构造方法没有对它做初始化,所以还是空指针的问题:

public final class TopicBuiltinTopicDataSeqHolder {public TopicBuiltinTopicData[] value;public TopicBuiltinTopicDataSeqHolder() {}public TopicBuiltinTopicDataSeqHolder(TopicBuiltinTopicData[] var1) {this.value = var1;}
}

那么问题来了,该把内部的数组初始化成多长呢?既然示例代码把最大采样量设为20,那先按这个数值试试,结果果不其然又报错了(这里只放出本地栈的信息):

Stack: [0x00000000021f0000,0x00000000022f0000],  sp=0x00000000022ee170,  free space=1016k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0x13f755]
C  [OpenDDS_DCPS_Javad.dll+0x9c929]  JNIEnv_::GetObjectClass+0x59
C  [OpenDDS_DCPS_Javad.dll+0xa2893]  copyToCxx+0x53
C  [OpenDDS_DCPS_Javad.dll+0xcd3a0]  copyToCxx+0xc0
C  [OpenDDS_DCPS_Javad.dll+0x113b6c]  Java_DDS__1TopicBuiltinTopicDataDataReaderTAOPeer_read+0xec
C  0x0000000002868c67

可以看到,这里两次进入copyToCxx方法(其实是两个不同的重载版本),并且又调用到GetObjectClass并出错,显然又出现空指针问题了,我们看最初进入的copyToCxx方法代码,发现,原来只要两个Holder其内部的数组有内容(即长度大于0),就会遍历并复制,所以答案就得到了:初始化两个Holder时,数组长度取0即可

正确代码如下:

        DomainParticipantFactory dpf = TheParticipantFactory.WithArgs(new StringSeqHolder(args));if (dpf == null) {return;}DomainParticipant dp = dpf.create_participant(4, PARTICIPANT_QOS_DEFAULT.get(), null, DEFAULT_STATUS_MASK.value);if (dp == null) {return;}// 订阅内置主题DCPSTopicSubscriber subscriber = dp.get_builtin_subscriber();DataReader dr = subscriber.lookup_datareader("DCPSTopic");TopicBuiltinTopicDataDataReader pdr = TopicBuiltinTopicDataDataReaderHelper.narrow(dr);TopicBuiltinTopicDataSeqHolder partData  = new TopicBuiltinTopicDataSeqHolder(new TopicBuiltinTopicData[0]);SampleInfoSeqHolder infos                = new SampleInfoSeqHolder(new SampleInfo[0]);int ret = pdr.read(partData, infos, 20, ANY_SAMPLE_STATE.value, ANY_VIEW_STATE.value, ANY_INSTANCE_STATE.value);if (ret == RETCODE_OK.value) {TopicBuiltinTopicData[] datas =  partData.value;for (TopicBuiltinTopicData data : datas) {String topicName = data.name;// do-something}}

运行后,没有再报错了

这篇关于记OpenDDS订阅内置主题的一些坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/272134

相关文章

基于Qt实现系统主题感知功能

《基于Qt实现系统主题感知功能》在现代桌面应用程序开发中,系统主题感知是一项重要的功能,它使得应用程序能够根据用户的系统主题设置(如深色模式或浅色模式)自动调整其外观,Qt作为一个跨平台的C++图形用... 目录【正文开始】一、使用效果二、系统主题感知助手类(SystemThemeHelper)三、实现细节

Python 内置的一些数据结构

文章目录 1. 列表 (List)2. 元组 (Tuple)3. 字典 (Dictionary)4. 集合 (Set)5. 字符串 (String) Python 提供了几种内置的数据结构来存储和操作数据,每种都有其独特的特点和用途。下面是一些常用的数据结构及其简要说明: 1. 列表 (List) 列表是一种可变的有序集合,可以存放任意类型的数据。列表中的元素可以通过索

python内置模块datetime.time类详细介绍

​​​​​​​Python的datetime模块是一个强大的日期和时间处理库,它提供了多个类来处理日期和时间。主要包括几个功能类datetime.date、datetime.time、datetime.datetime、datetime.timedelta,datetime.timezone等。 ----------动动小手,非常感谢各位的点赞收藏和关注。----------- 使用datet

C++编程:ZeroMQ进程间(订阅-发布)通信配置优化

文章目录 0. 概述1. 发布者同步发送(pub)与订阅者异步接收(sub)示例代码可能的副作用: 2. 适度增加缓存和队列示例代码副作用: 3. 动态的IPC通道管理示例代码副作用: 4. 接收消息的超时设置示例代码副作用: 5. 增加I/O线程数量示例代码副作用: 6. 异步消息发送(使用`dontwait`标志)示例代码副作用: 7. 其他可以考虑的优化项7.1 立即发送(ZMQ_IM

Linux内置的审计跟踪工具:last命令

如果你是一个服务器管理员,你或许知道你要保护你的服务器的话,不仅是从外部,还要从内部保护。Linux有一个内置工具来看到最后登陆服务器的用户,可以帮助你保护服务器。   这个命令是last。它对于追踪非常有用。让我们来看一下last可以为你做些什么。   last命令的功能是什么   last显示的是自/var/log/wtmp文件创建起所有登录(和登出)的用户。这个文件是二进制

内置带so的APK为系统APK方法

(1)若内置为可卸载的APK,可以无需解压出lib直接编译就可以 具体参考http://blog.csdn.net/a462533587/article/details/46380795 (2)若内置为system APP,上述blog也有两种方式: 方法一:   如下例,在Android.mk中添加并配置变量(注意路径对应): LOCAL_PREBUILT_JNI_LIBS = \

请解释JSP中的九大内置对象及其作用。什么是Java Web中的请求转发和重定向?它们有什么区别?

请解释JSP中的九大内置对象及其作用。 JSP(JavaServer Pages)中的九大内置对象(也称为隐式对象或自动对象)是JSP容器为每个页面提供的Java对象,这些对象在JSP页面被转换成Servlet时自动可用,无需显式声明。这些对象极大地简化了JSP页面的开发,因为它们提供了对Web应用程序中常见功能的直接访问。以下是九大内置对象及其作用的详细解释: request:javax.

最强虚拟机,内置强大插件,绝!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 天给大家安利两款移动端的虚拟机软件,均支持超级权限、Xposed框架和谷歌服务,而其中一款可谓称得上最强虚拟机,不仅含有虚拟机的基本功能,还能多开分身、模拟器以及强大的插件社区,能实现的功能超乎你的想象,一起来看看吧! X8沙箱(安卓) 软件介绍 X8沙箱(手机版的安卓模拟器、虚拟机、多开分身、游戏双开多开挂机)是一款极简、

VitePress 自定义主题:打造专属文档网站

VitePress 是一个基于 Vite 和 Vue 3 的静态网站生成器,特别适用于撰写文档。它不仅提供了默认的主题,还允许开发者创建和使用自定义主题,以满足特定的设计和功能需求。本文将详细介绍如何创建、使用及分发 VitePress 自定义主题,并通过实例代码进行演示。 一、创建自定义主题 1. 主题文件结构 要启用自定义主题,你需要在项目根目录下的 .vitepress 文件夹中创建一