目录

一.准备

二.发送消息:TestPublisher

三.接收消息:TestSubscriber & DataReaderListenerImpl

四.在IDEA中运行示例


一.准备

首先需要安装好OpenDDS并开启Java支持:Windows下OpenDDS安装

然后在IDEA创建空项目

Java开发OpenDDS需要以下jar包:

其中 messenger_idl_test.jar 是自带示例的包,并不是必需的,这里因为基于示例进行修改,所以还是要引入

引入方法:

File菜单 - Project Structure -Libraries - 点击"+"号 - Java ,然后定位到 %DDS_ROOT%\lib,选中三个jar包,messenger_idl_test.jar同理

注:由于OpenDDS需要CORBA,而Java 9开始移除了CORBA,所以请在Java 8环境下开发,或者引入1.8版本的rt.jar

然后去%DDS_ROOT%\java\tests\messenger下,将publisher和subscriber两个目录下的TestPublisher、TestSubscriber、DataReaderListenerImpl三个java文件复制到IDEA项目的src目录下:

二.发送消息:TestPublisher

        DomainParticipantFactory dpf =TheParticipantFactory.WithArgs(new StringSeqHolder(args));DomainParticipant dp = dpf.create_participant(4,PARTICIPANT_QOS_DEFAULT.get(), null, DEFAULT_STATUS_MASK.value);

第一行用来创建域参与者工厂,需要读取参数(实际上就是读取repo.ior文件)

第二行是创建具体的域参与者,create_participant方法的定义(实际在DomainParticipantFactoryImpl.cpp文件中)为:

DDS::DomainParticipant_ptr
DomainParticipantFactoryImpl::create_participant(DDS::DomainId_t domainId,const DDS::DomainParticipantQos & qos,DDS::DomainParticipantListener_ptr a_listener,DDS::StatusMask mask)
{DDS::DomainParticipantQos par_qos = qos;if (par_qos == PARTICIPANT_QOS_DEFAULT) {get_default_participant_qos(par_qos);}if (!Qos_Helper::valid(par_qos)) {ACE_ERROR((LM_ERROR,ACE_TEXT("(%P|%t) ERROR: ")ACE_TEXT("DomainParticipantFactoryImpl::create_participant, ")ACE_TEXT("invalid qos.\n")));return DDS::DomainParticipant::_nil();}if (!Qos_Helper::consistent(par_qos)) {ACE_ERROR((LM_ERROR,ACE_TEXT("(%P|%t) ERROR: ")ACE_TEXT("DomainParticipantFactoryImpl::create_participant, ")ACE_TEXT("inconsistent qos.\n")));return DDS::DomainParticipant::_nil();}RcHandle<DomainParticipantImpl> dp =make_rch<DomainParticipantImpl>(this, domainId, par_qos, a_listener, mask);if (qos_.entity_factory.autoenable_created_entities) {if (dp->enable() != DDS::RETCODE_OK) {ACE_ERROR((LM_ERROR,ACE_TEXT("(%P|%t) ERROR: ")ACE_TEXT("DomainParticipantFactoryImpl::create_participant, ")ACE_TEXT("unable to enable DomainParticipant.\n")));return DDS::DomainParticipant::_nil();}}ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex,tao_mon,this->participants_protector_,DDS::DomainParticipant::_nil());participants_[domainId].insert(dp);return dp._retn();
}

主要就是进行Qos的验证,然后创建DomainParticipantImpl对象,调用其enable方法以激活,然后添加到参与者组中。参与者组实质是个Map,以域ID作为key。

接下来是创建主题:

MessageTypeSupportImpl servant = new MessageTypeSupportImpl();
Topic top = dp.create_topic("Movie Discussion List",servant.get_type_name(),TOPIC_QOS_DEFAULT.get(),null,DEFAULT_STATUS_MASK.value);

需要注意的是,OpenDDS的主题和发送的消息,必须在发送时就全部确定,不能用Scanner接受用户输入然后动态创建

create_topic方法实际调用的是create_topic_i方法,添加了一个topic_mask参数(值为0),整个方法有150+行,仅挑些重点:

首先还是Qos检查,略过

接下来是根据主题名检查主题有没有创建过(假如开启了主题过滤,并且不允许重复主题,则直接退出):

TopicMap::mapped_type* entry = 0;bool found = false;{ACE_GUARD_RETURN(ACE_Recursive_Thread_Mutex,tao_mon,this->topics_protector_,DDS::Topic::_nil());#if !defined(OPENDDS_NO_CONTENT_FILTERED_TOPIC) || !defined(OPENDDS_NO_MULTI_TOPIC)if (topic_descrs_.count(topic_name)) {if (DCPS_debug_level > 3) {…… //一些报错信息}return 0;}
#endifif (Util::find(topics_, topic_name, entry) == 0) {found = true;}}

假如同名主题已经创建过了,则进行type和qos的比较,如果有一个不符合,则返回空,创建失败,如果都符合,说明主题已经存在,就直接返回主题对象

假如同名主题不存在,则创建新主题:

首先要检查欲创建的主题类型有没有注册过:

    if (0 == topic_mask) {// creating a topic with compile time typetype_support = Registered_Data_Types->lookup(this, type_name);if (CORBA::is_nil(type_support)) {if (DCPS_debug_level >= 1) {…… //报错}return DDS::Topic::_nil();}has_keys = type_support->has_dcps_key();}

接下来就是对topic信息的检查,以及初始化Topic对象的过程,如果设置了TopicListener的话,创建完毕后会进行回调

接下来是创建Publisher对象;

Publisher pub = dp.create_publisher(PUBLISHER_QOS_DEFAULT.get(), null,DEFAULT_STATUS_MASK.value);

其C++代码流程和create_participant类似,不同的是,保存Publisher对象的是个集合而非Map,还有Publisher的ID是用一个内置的ID生成器自动产生的

接下来是创建DataWriter对象, 为之配置了非常复杂的Qos策略,并等待Publisher匹配成功

到这里准备工作才刚刚结束,下面开始正式的数据发送

        MessageDataWriter mdw = MessageDataWriterHelper.narrow(dw);Message msg = new Message();msg.subject_id = 99;int handle = mdw.register_instance(msg);msg.from = "OpenDDS-Java";msg.subject = "Review";msg.text = "Worst. Movie. Ever.";msg.count = 0;int ret = RETCODE_TIMEOUT.value;for (; msg.count < N_MSGS; ++msg.count) {while ((ret = mdw.write(msg, handle)) == RETCODE_TIMEOUT.value) {}if (ret != RETCODE_OK.value) {System.err.println("ERROR " + msg.count +" write() returned " + ret);}try {Thread.sleep(100);} catch(InterruptedException ie) {}}

MessageDataWriter是messenger_idl_test包含的DataWriter子类,实际执行Message发送任务,Message的格式由Messenger.idl定义。for循环一共发送40条消息。

假如启动时加了-w参数,则会等待响应,否则等待1秒后直接进行清理、退出

三.接收消息:TestSubscriber & DataReaderListenerImpl

TestSubscriber的整个流程和TestPublisher几乎完全一致,不同的是,创建DataReader时,会将DataReaderListenerImpl实例传入。

当Publisher向域中输入消息后,就会触发DATA_AVAILABLE事件,通知DataReaderListenerImpl处理

    public synchronized void on_data_available(DataReader reader) {initialize_counts();MessageDataReader mdr = MessageDataReaderHelper.narrow(reader);if (mdr == null) {System.err.println("ERROR: read: narrow failed.");return;}MessageHolder mh = new MessageHolder(new Message());SampleInfoHolder sih = new SampleInfoHolder(new SampleInfo(0, 0, 0,new Time_t(), 0, 0, 0, 0, 0, 0, 0, false, 0));int status = mdr.take_next_sample(mh, sih);if (status == RETCODE_OK.value) {System.out.println("SampleInfo.sample_rank = "+ sih.value.sample_rank);System.out.println("SampleInfo.instance_state = "+ sih.value.instance_state);if (sih.value.valid_data) {String prefix = "";boolean invalid_count = false;if (mh.value.count < 0 || mh.value.count >= counts.size()) {invalid_count = true;}else {if (counts.get(mh.value.count) == false){counts.set(mh.value.count, true);}else {prefix = "ERROR: Repeat ";}}…… //消息内容输出}…… //一些报错} else if (status == RETCODE_NO_DATA.value) {System.err.println("ERROR: reader received DDS::RETCODE_NO_DATA!");} else {System.err.println("ERROR: read Messenger.Message: Error: " + status);}}

程序使用MessageHolder存储读到的信息,每次读取一条

四.在IDEA中运行示例

运行run_test.pl脚本时,可以看到类似:

"C:\Program Files\Java\bin\java.EXE" -Xcheck:jni -ea -cp classes;E:\OpenDDS-3.13/lib/i2jrt.jar;E:\OpenDDS-3.13/lib/OpenDDS_DCPS.jar;E:\OpenDDS-3.13/java/tests/messenger/messenger_idl/messenger_idl_test.jar;publisher/classes -Dopendds.native.debug=true TestPublisher -DCPSBit 0 -DCPSConfigFile tcp.ini -r -w

的命令输出,可以参照这个配置运行条件

1)首先配置虚拟机选项:

Run菜单 - Edit Configurations,在 vm options 一栏填写:

-ea -Dopendds.native.debug=true -Djava.library.path=E:\OpenDDS-3.13/java/tests/messenger/messenger_idl;E:\OpenDDS-3.13\lib

请按照自己的实际情况修改路径。由于已经配置了jar包,所以不需要再写-cp选项。

-Djava.library.path是用来配置JNI库路径,不写的话会提示找不到dll

去除 -Xcheck:jni 是为了屏蔽掉过多的JNI Warning

2)然后配置主程序参数:

在同一个窗口的 Program arguments一栏填写:

-DCPSBit 0 -DCPSConfigFile E:\OpenDDS-3.13/java/tests/messenger/tcp.ini 

同样按照自己的实际情况修改路径。这一行如果写在vm options中,就会提示”ERROR: Domain Participant Factory not found

“,因为参数传递给了虚拟机而不是程序,导致无法创建DomainParticipantFactory

3)运行实例

按照以上配置,分别创建TestPublisher和TestSubscriber两个启动实例

然后在命令行运行:

 %DDS_ROOT%/bin/DCPSInfoRepo -o repo.ior

接着修改tcp.ini,将common块DCPSInfoRepo项的值修改成repo.ior所在位置,不要去掉"file://"前缀

然后按照先subscriber,后publisher的顺序启动程序即可

OpenDDS Java开发(一):理解Messenger示例相关推荐

  1. java开发工程师每天工作几小时,详细说明

    Java开发工程师前途在哪里?常听到有人这么说:现在Java开发工程师的前途在哪儿?如何成为一名优秀的Java工程师?我的路该怎么走?很多人想着自己初出茅庐,不知这个专 Java工程师人才的需求还在不 ...

  2. 阿里JAVA开发手册零度的思考理解(二)

    转载请注明原创出处,谢谢! 说在前面 人生的大道上默默地走,就必须要有一盏灯亮着为你引导方向!而这盏灯抑或只是一句话,一句鼓励,一个赞美,一次承认,一次认可,一次相识一次交流-- 上篇文章:阿里JAV ...

  3. 深入理解Java反射+动态代理,java开发面试笔试题

    我总结出了很多互联网公司的面试题及答案,并整理成了文档,以及各种学习的进阶学习资料,免费分享给大家. 扫描二维码加VX好友,拉你进[程序员面试学习交流群]免费领取.也欢迎各位一起在群里探讨技术. 答: ...

  4. Java开发工具IntelliJ IDEA创建Andriod项目示例说明

    IntelliJ IDEA社区版作为一个轻量级的Java开发IDE,是一个开箱即用的Android开发工具. 注意:在本次的教程中我们将以Android平台2.2为例进行IntelliJ IDEA的使 ...

  5. IO输入输出模型是每个Java开发人员必须理解的重点,深度解析跳槽从开始到结束完整流程

    关于数据流 ===== 在数据输入输出描述中,我们抽象出了一个概念叫做流Stream, 简单数来就是从一个点到另外一个点的数据有序流动,或者说是一个任意长度的有序字节序列. 在Java编程中,我们为了 ...

  6. java开发机器人聊天_聊天机器人与Web开发的未来

    java开发机器人聊天 Since Facebook launched their annual F8 conference for bot developers in 2016 and Micros ...

  7. java string 占位符_驳《阿里「Java开发手册」中的1个bug》?

    前两天写了一篇关于<阿里Java开发手册中的 1 个bug>的文章,评论区有点炸锅了,基本分为两派,支持老王的和质疑老王的. 首先来说,无论是那一方,我都真诚的感谢你们.特别是「二师兄」, ...

  8. 10个Java 8 Lambda表达式经典示例

    Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表 达式,它将允许我们将行为传到函数里.在J ...

  9. 阿里巴巴 Java 开发手册之编程规约(一)-------我的经验

    阿里巴巴 Java 开发手册 一.编程规约 (一) 命名规约 1.[强制] 代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束.(代码规范,易读) 反例: _name / __na ...

最新文章

  1. 无线数据采集器与计算机系统的连接,WS5、WS6 WiFi无线数据采集器,如何与计算机实现无线远距离采集...
  2. 获取有效工作日封装类(原创)
  3. 10W学习笔记——查询之联接
  4. 《javascript高级程序设计》笔记:原型图解
  5. 爬虫爬取链接中文字_使用爬虫技术爬取图片链接并下载图片
  6. ViewState机制的解析(转自csdn)
  7. linux 添加环境变量(php为例)
  8. 华威、剑桥与三星联合提出基于时间核一致性的盲视频超分辨率
  9. 背不下《道德经》,至少背下这10句精华!
  10. 如果美图可以把妹,如何用技术手段做一个会拍照的程序员?
  11. iOS实现文字渐变效果
  12. ApacheCN 翻译活动进度公告 2019.3.3
  13. 数据库系统概论-数据库设计
  14. 2021年全球排烟扇收入大约181百万美元,预计2028年达到198.7百万美元
  15. 一款开源好用的车辆管理系统源码,基于SSH框架和SaaS模式
  16. [操作系统]进程同步 Reader-Writer问题 共享缓冲区问题 面包师问题 吸烟者问题
  17. mysql force index 语法_MySQL FORCE INDEX 强制索引使用
  18. 自媒体爆文标题怎么写?6种实用小技巧分享!
  19. 华为手机不能支持5G,研发创新科技解决,M国的做法落空
  20. 【2】基因功能注释之SwissProt和Interproscan

热门文章

  1. matlab生成不同的椭圆,[平面几何][Matlab] 平面椭圆参数与一般式之间的转换
  2. JavaWeb和WebGIS学习笔记(三)——GeoServer 发布shp数据地图
  3. 久等了的QIIME 2 2020.2 更新来了
  4. Java代码防止被反编译的4中方法
  5. Python计算代码的执行时间
  6. java虚拟机的内存管理
  7. Hadoop源码编译介绍-尚硅谷大数据培训
  8. 计算机视觉面试题总结
  9. windos10本地安装git工具并使用
  10. 全国最搞笑的名字都在这了,看了不准笑!