目录
1.编写IDL文件
IDL是Interface description language的缩写,指接口描述语言,是CORBA规范的一部分,是跨平台开发的基础。
关于IDL的介绍可参见:https://blog.csdn.net/wyc12306/article/details/79577389
这里以Messenger示例中的Messenger.idl为例说明:
module Messenger {
#pragma DCPS_DATA_TYPE "Messenger::Message"
#pragma DCPS_DATA_KEY "Messenger::Message subject_id"
struct Message {
string from;
string subject;
long subject_id;
string text;
long count;
};
};
它由三部分组成:
- module:最外层,可以理解为待生成的工程名字
- pragma指令:指定了OpenDDS项目中传输的数据类型和键,每个数据类型可以有零到多个键,键的作用是标识不同的实例
- struct:pragma指令指定的数据类型
在本例的Message结构体中,有5个成员,为字符串或数字类型,在IDL中,主要有如下类型:
基本类型:
1)整数类型:short(2字节)、long(4字节)、long long(8字节),及它们的无符号类型
2)浮点型:float(4字节)、double(8字节)、long double(16字节)
3)字符型:char、wchar、string、wstring
4)布尔型:boolean
5)八进制型:octet
结构类型有struct、interface、union等。
一般常用的就是string、double、long、boolean这几个。
在同一个module下,可以编写很多个struct,并且可以为每一个struct都添加#pragma指令,为了简化,还是只以一个为例,现在创建一个名为UserManager的module,其中包含User结构体,每个User都包含姓名(string)、性别(以boolean表示,true代表男,false代表女,反过来也一样)、年龄(long)、身高(double)和一个唯一ID(long):
module UserManager {
#pragma DCPS_DATA_TYPE "UserManager::User"
#pragma DCPS_DATA_KEY "UserManager::User id"
struct User {
long id;
string name;
boolean sexual;
long age;
double height;
};
};
2 将IDL编译为C++代码
官方文档第10章描述是通过编写mpc文件生成sln工程,直接将C++和Java代码都生成出来,我实际测试是不行的。必须先按照第2章的步骤生成C++代码之后,才能再按照第10章的步骤生成Java代码。
编译时需要利用C++编译器,如果是Windows环境,可以在Visual Studio的开发人员命令行下运行。首先使用tao_idl.exe编译刚刚编写的idl文件:
E:\OpenDDS-3.13>tao_idl UserManager.idl
tao-idli_2AUI68.cpp
processing UserManager.idl
此时会生成:UserManagerC.cpp、UserManagerC.h、UserManagerC.inl、UserManagerS.cpp、UserManagerS.h五个文件
然后使用opendds_idl进行编译:
E:\OpenDDS-3.13>opendds_idl UserManager.idl
tao-idli_VTx7fz.cpp
processing UserManager.idl
此时生成了:UserManagerTypeSupport.idl、UserManagerTypeSupportImpl.cpp、UserManagerTypeSupportImpl.h三个文件
对新生成的UserManagerTypeSupport.idl同样使用tao_idl进行编译
3 将已生成代码编译为Java代码
首先按第10章步骤,生成UserManager_Export.h(这个名字可以随便起,只要下面的mpc文件和这里保持一致即可):
E:\OpenDDS-3.13>generate_export_file.pl UserManager>UserManager_Export.h
然后编写mpc文件以生成工程,可以把%OPENDDS_HOME%\java\tests\messenger\messenger_idl目录下的messenger_idl_test.mpc拷出来改一下:
project: dcps_test_java {
idlflags += -Wb,stub_export_include=UserManager_Export.h \
-Wb,stub_export_macro=UserManager_Export
dcps_ts_flags+= -Wb,export_macro=UserManager_Export
idl2jniflags += -Wb,stub_export_include=UserManager_Export.h \
-Wb,stub_export_macro=UserManager_Export
dynamicflags += UserManager_BUILD_DLL
specific {
jarname = UserManager
}
TypeSupport_Files {
UserManager.idl
}
}
然后进行编译:
E:\OpenDDS-3.13>mwc.pl -type vs2017 UserManager.mpc
此时应该可以生成sln文件,如果出现下面的异常,可考虑使用mpc.pl进行编译,它会产生vcxproj文件:
Using .../OpenDDS-3.13/ACE_wrappers/bin/MakeProjectCreator/config/MPC.cfg
CIAO_ROOT was used in the configuration file, but was not defined.
DANCE_ROOT was used in the configuration file, but was not defined.
Generating 'vs2017' output using UserManager.mpc
UserManager.mpc: line 1:
ERROR: No workspace was defined
ERROR: Unable to process: UserManager.mpc
注意,上面的-type选项的值需要根据实际情况确定,我使用的VS 2019经测试可以打开和编译VS 2017工程。
接下来,打开工程,会提示设置Windows SDK,直接确认即可,如果电脑是64为系统,需要将上方“Debug”旁边的x86换成x64,接着,执行“生成”-“生成解决方案”即可。
在生成过程中,可能会提示缺少 jni_md.h,该文件位于 %JAVA_HOME%\include\win32 目录下,复制到 %OPENDDS_HOME%\java\idl2jni\runtime 目录下即可。
此时,按照我们刚刚编写的mpc文件,就可以得到UserManager.jar 和 UserManagerd.dll(因为是Debug模式下生成,如果是Release模式则不会有d),剩下的文件都可以删除了。
4 使用UserManager替换Messenger
我们打开 OpenDDS Java开发(一):理解Messenger示例 中创建的工程,稍作修改。
首先是移除对messenger_idl_test.jar的依赖,并添加UserManager.jar。此时三个java文件肯定都会报错标红,把这些地方都改掉就好。
对TestPublisher进行修改:
第1处:
MessageTypeSupportImpl servant = new MessageTypeSupportImpl();
-> 修改为:
UserTypeSupportImpl servant=new UserTypeSupportImpl();
第2处:
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) {
}
}
-> 修改为:
UserDataWriter writer=UserDataWriterHelper.narrow(dw);
User user=new User();
int handle=writer.register_instance(user);
user.name="zhangsan";
user.age=20;
user.sexual=true;
user.height=1.75;
user.id=1;
writer.write(user,handle);
对TestSubscriber进行修改:
MessageTypeSupportImpl servant = new MessageTypeSupportImpl();
-> 修改为:
UserTypeSupportImpl servant=new UserTypeSupportImpl();
对DataReaderListenerImpl进行修改,先把Message全替换成User:
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 ";
}
}
System.out.println(prefix + "Messenger.User: subject = " + mh.value.subject);
System.out.println(" subject_id = "
+ mh.value.subject_id);
System.out.println(" from = " + mh.value.from);
System.out.println(" count = " + mh.value.count);
System.out.println(" text = " + mh.value.text);
System.out.println("SampleInfo.sample_rank = "
+ sih.value.sample_rank);
-> 修改为:
System.out.println("User "+mh.value.id+":{name:"+mh.value.name+",age:"+mh.value.age+",sexual:"+(mh.value.sexual?"male":"female")+",height:"+mh.value.height+"}");
然后把VM option中的 -Djava.library.path 修改为:
-Djava.library.path=<UserManager.jar所在路径>;E:\OpenDDS-3.13\lib
因为-DCPSConfigFile选项没改,所以还是在messenger示例目录下运行DCPSInfoRepo,分别运行TestPublisher和TestSubscriber后,在订阅者一端打印了如下消息,说明替换成功:
User 1:{name:zhangsan,age:20,sexual:male,height:1.75}