目錄
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}