现在很多人在对corba进行学习,大家都已经了解到corba是一个完全中间性的语言,可以使用接口定义语言(idl)定义开发时使用接口的 client 和实现接口的 server 所需要的信息。client 和 server 的具体实现代码并不在idl定义中编写,而是使用某种目标语言的idl 编译器生成所需的代码存根及helper类,client 和 server再使用真正的编程语言来进行具体实现。
为了保证在不同的 corba 产品基础之上构建的分布式对象可以相互通信,client和server通过orb(对象请求代理)进行通信。一般的运行流程是client把请求发送给orb,orb再把请求发送给server,server把返回结果发送orb,orb再把返回结果发送给client。orb可以说client和server之间的翻译者。即使client和server使用不同的编程语言编写,只要是符合相同的idl定义,orb也可以完成相互的通信。
所有的文档在强调服务器及客户机可以是java也可以是c++或其他语言(如:delphi)进行编写,但在网站或书本是没有详细说如何应对多语言客户机的例子。《java2核心技术》上面有些说明,但也只是介绍性的文章,故自己下载了omniorb304,进行了一次使用sun的 tnameserv命名服务程序,服务器用java编写,客户机分别用java和c++(vc6+omniorb)编写的试验,希望通过一次编程的具体操作实例来体验或明了corba思想。
总体的编写过程如下:
用idl定义一个接口文件,描绘要实现的功能,也可以说是定义一个要实现功能的一个模版(sysprop.idl)
使用"idl to java"编译器(这里是idlj)将idl文件转化为java编程语言中编写的接口定义,生成所需的代码存根及helper类
使用java语言编写客户机和服务器的实现程序。
使用"idl to c++"编译器(这里是omniidl)将idl文件转化为c++编程语言中编写的接口定义,生成所需的代码存根及helper类
使用c++语言编写客户机实现程序(当然也可编写服务器程序,但本次试验没有进行)
起动命名服务tnameserv
起动java编写的服务程序
用java和c++编写的客户机分别调用相应的服务
2. 运行环境的设定:
总体环境由jdk1.3+omniorb3.0(www.uk.research.att.com/omniorb/doc/3.0) +vc6 组成,下面说明具体的安装。
2.1. 安装jdk1.3
从sun公司down jdk1.3或者通过其他方式得到jdk1.3进行安装,再设定相应的环境变量,在本文测试用的电脑上是如下所示:
classpath=.;
java_home=d:/jdk130
修改原来的path变量,添加"%java_home%/bin;",如下
ptah=%java_home%/bin;原变量
注意:我在第一次使用jbuilder的jdk1.3时,服务器不能正常工作,我只是发觉这么一回事,具体原因与本文无关而没有进行了解,请谅。
2.2. 安装vc6
vc6按常规方式安装,注意的是:在本文测试用的电脑上安装在如下位置
c:/program files/microsoft visual studio
2.3.安装omniorb
从 www.uk.research.att.com/omniorb/doc/3.0 下载omniorb3.0 ( 本文测试所下载的文件是omniorb_304_x86_win32.zip )。
用winzip进行解压omniorb_304_x86_win32.zip到omniorb_304_x86_win32目录,目录内存在omni目录,复制omni目录内的文件到你把想存放的位置。
测试电脑安装在c:/omni
根据c:/omni/readme.win32 文档进行设定,由于运行程序及命令行在控制台进行,所以本次测试并不根据文档要求去设定环境变量,而是编写了一个omni.bat,在使用控制台时,首先运行。
本测试电脑omni.bat内容如下
| set top=c:/omni set path=%top%/bin/x86_win32;%path% set lib=%top%/bin/x86_win32;%lib% set include=%top%/include;%include% set vcosdir= set vscommondir= |
如果你的电脑vc的环境变量已经设定在你的环境变量中,那么c:/program files/microsoft visual studio/vc98/bin/vcvars32.bat 就可以不运行。否则运行omni.bat前要首先运行vcvars32.bat。
3. 实践过程约定所有编写的文件保存在d:/mywork/t1中,omni.bat也在这个目录内
3.1.编写sysprop.idl,功能是返回系统属性
| interface sysprop { string getproperty(in string name); }; |
3.2. 编写java的服务器
3.2.1. 把idl文件转化为java编程语言代码存根类及helper类。
执行如下命令
idlj -fall sysprop.idl
在正常的情况下d:/mywork/t1 目录内将生成以下文件,否则请检查你的执行程序及文件
sysprop.java sysprophelper.java syspropholder.java syspropoperations.java _syspropimplbase.java _syspropstub.java |
3.2.2. 编写 syspropserver.java
import org.omg.cosnaming.*; //编写相对应的服务,一定要从 _类名implbase继承,并实现相应的方法 { public string getproperty(string key) |
3.3. 编写java的客户机
3.3.1. 编写 syspropclient.java 使用ior字符串的方式
注意在代码内有一段注解掉的代码,用"//使用orb的方法的开始"开始,用"//使用orb的方法的结束"结束。这段代码是使用orb方法的代码,如果在代码中"//使用ior的方法开始"前一行添加"/*",在"//使用ior的方法结束"后一行添加"*/",而把"//使用orb的方法的开始"前面的"/*"去掉,把"//使用orb的方法的结束"后面的"*/"去掉,就是使用orb方法的代码,程序运行时就是" syspropclient [环境变量] "的方式。以下是具体代码:
import org.omg.cosnaming.*; /* |
3.3.2. 编译程序,在文件目录内执行如下命令
javac *.java
3.4. 进行测试
第1控制台,执行
tnameserv
测试时如下所示
| d:/mywork/t1>java tnameserv initial naming context: ior:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f 6e746578743a312e3000000000010000000000000054000101000000000c3139322e3136382e302e 31000ca6000000000018afabcafe00000002a999c474000000080000000000000000000000010000 0001000000140000000000010020000000000001010000000000 transientnameserver: setting port for initial object references to: 900 ready. |
第2控制台,执行
java syspropserver
测试时如下所示
| d:/mywork/t1>java syspropserver 创建和初始化 orb 创建服务对象并将其向 orb 注册 ior:000000000000001049444c3a53797350726f703a312e30000000000100000000000000540001 01000000000c3139322e3136382e302e31000ca7000000000018afabcafe00000002a999dbeb0000 00080000000000000000000000010000000100000014000000000001002000000000000101000000 0000 绑定服务...sysprops 等待调用...sysprops |
第3控制台,执行
java syspropclient ior:xxx java.home
测试时如下所示
| d:/mywork/t1>java syspropclient ior:000000000000001049444c3a53797350726f703a312e 3000000000010000000000000054000101000000000c3139322e3136382e302e31000ca700000000 0018afabcafe00000002a999dbeb0000000800000000000000000000000100000001000000140000 000000010020000000000001010000000000 java.home 开始调用 java.home=d:/bea/jdk130/jre |
3.5. 编写c++的ior客户机
从实践来讲编写c++的客户机程序同java没有多大的区别,只不过java是用idlj生成代码存根类及helper类,而omni是用omniidl来生成代码存根类及helper类,而编程思想及编码过程非常相似。
由于c++的程序要调用omni及vc6的相关文件,所以进入控制台后,如果vc没有进行环境变量设定,那么要先运行c:/program files/microsoft visual studio/vc98/bin/vcvars32.bat,再运行omni.bat,否则直接运行omni.bat后再编译程序及运行程序。
3.5.1. 把idl文件转化为c++编程语言代码存根类及helper类。
执行如下命令
omniidl -bcxx sysprop.idl
在正常的情况下d:/mywork/t1 目录内将生成c++编程语言的代码存根类及helper类sysprop.hh和syspropsk.cc。否则请检查你的执行程序及文件。
3.5.2. 编写syspropc.cc
| #include #include int main(int argc, char** argv) { try { corba::orb_var orb = corba::orb_init(argc, argv, "omniorb3"); if( argc < 2 || argc > 3 ) { cout << "usage: syspropc return 1; } corba::object_var obj = orb->string_to_object(argv[1]); sysprop_ptr echoref = sysprop::_narrow(obj); if( corba::is_nil(echoref) ) { cerr << "没有对象" << endl; return 1; } const char* message; if (argc==3) { message=argv[2]; } else { message="java.home"; } corba::string_var dest = echoref->getproperty(message); cout << (char*)message << "=" <<(char*)dest << endl; orb->destroy(); } catch(...) { cerr << "caught unknown exception." << endl; } return 0; } |
3.5.3. 编写dirc.mak,如下所示
| top = c:/omni omni_dynamic_lib = msvcstub.lib -nodefaultlib:libcmt.lib -nodefaultlib:libcmtd.lib corba_cppflags = -d__win32__ -d__x86__ -d__nt__ -d__osversion__=4 corba_lib = omniorb304_rt.lib omnithread2_rt.lib / $(omni_dynamic_lib) / wsock32.lib advapi32.lib / -libpath:$(top)/lib/x86_win32 cxxflags = -o2 -md -gx $(corba_cppflags) $(dir_cppflags) cxxlinkoptions = .suffixes: .cc .cc.obj: cl /nologo /c $(cxxflags) /tp$< all:: syspropc.exe syspropc.exe: syspropsk.obj syspropc.obj link -nologo $(cxxlinkoptions) -out:$@ $** $(corba_lib) clean:: -del *.obj -del *.exe veryclean:: -del *.obj -del echosk.* echo.hh -del *.exe sysprop.hh syspropsk.cc: sysprop.idl $(top)/bin/x86_win32/omniidl -t -bcxx -wbh=.hh -wbs=sk.cc -wbtp sysprop.idl |
3.5.4. 编译程序,执行如下命令
nmake -f dirc.mak
3.5.5. 测试
在第4控制台
syspropc ior:xxx java.home
本测试如下所示
| d:/mywork/t1>syspropc ior:000000000000001049444c3a53797350726f703a312e3000000000 010000000000000054000101000000000c3139322e3136382e302e31000ca7000000000018afabca fe00000002a999dbeb00000008000000000000000000000001000000010000001400000000000100 20000000000001010000000000 os.name os.name=windows 2000 |
3.6. 编写c++的name方式客户机
为了使用nane方式,必须为omni软件设置注册表信息,要在注册表中建立如下数据项(regedit)hkey_local_machine/software/orl/omniorb/2.0/nameservice(字符串)。
nameservice的值为tnameserv(jdk1.3/bin内的程序)启动的ior值(第一次设置时自行添加)。
注意为了使用这种方式每次起动tnameserv后要用新ior值换去旧的ior值,我测试过用omini的omninames.exe程序做服务器,ior值是不变的,但服务器用jvav编写就会出错。如果起动tnameserv,用 c编写的服务器及客户机就可以在上面运行。本例子如下所示
| initial naming context: ior:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f 6e746578743a312e3000000000010000000000000054000101000000000c3139322e3136382e302e 31000ca6000000000018afabcafe00000002a999c474000000080000000000000000000000010000 0001000000140000000000010020000000000001010000000000 transientnameserver: setting port for initial object references to: 900 ready. |
那么就要把从 ior:开始(含ior:)后面的字符串放进注册表。
3.6.1.编写syspropcc.cc
| //使用name方式的客户机 #include #include "sysprop.hh" static corba::object_ptr getobjectreference(corba::orb_ptr orb); int main (int argc, char **argv) { if( argc != 2 ) { cout << "使用方法: syspropcc <环境变量名>" << endl; return 1; } try { corba::orb_var orb = corba::orb_init(argc, argv, "omniorb3"); corba::object_var obj = getobjectreference(orb); sysprop_ptr echoref = sysprop::_narrow(obj); const char* message; if (argc==2){message=argv[1];} else {message="java.home"; } corba::string_var dest = echoref->getproperty(message); cout << (char*)message << "=" <<(char*)dest << endl; orb->destroy(); } catch(...) { cerr << "caught unknown exception." << endl; } return 0; } ////////////////////////////////////////////////////////////////////// static corba::object_ptr getobjectreference(corba::orb_ptr orb) { cosnaming::namingcontext_var rootcontext; try { // 定位服务器: corba::object_var obj; obj = orb->resolve_initial_references("nameservice"); // narrow the reference returned. rootcontext = cosnaming::namingcontext::_narrow(obj); if( corba::is_nil(rootcontext) ) { cerr << " 初始化不成功." << endl; return corba::object::_nil(); } } catch(corba::orb::invalidname& ex) { cerr << " 没有找到服务" << endl; return corba::object::_nil(); } cosnaming::name name; name.length(1); name[0].id = (const char*) "sysprop"; name[0].kind = (const char*) ""; try { // resolve the name to an object reference. return rootcontext->resolve(name); } catch(...) { cerr << "定位不成功." << endl;} return corba::object::_nil(); } |
3.6.2. 编写dircc.mak
| top = c:/omni dir_cppflags = -i. -i$(top)/include omni_dynamic_lib = msvcstub.lib -nodefaultlib:libcmt.lib -nodefaultlib:libcmtd.lib corba_cppflags = -d__win32__ -d__x86__ -d__nt__ -d__osversion__=4 corba_lib = omniorb304_rt.lib omnithread2_rt.lib / $(omni_dynamic_lib) / wsock32.lib advapi32.lib / -libpath:$(top)/lib/x86_win32 cxxflags = -o2 -md -gx $(corba_cppflags) $(dir_cppflags) cxxlinkoptions = .suffixes: .cc .cc.obj: cl /nologo /c $(cxxflags) /tp$< all:: syspropcc.exe syspropcc.exe: syspropsk.obj syspropcc.obj link -nologo $(cxxlinkoptions) -out:$@ $** $(corba_lib) clean:: -del *.obj -del *.exe veryclean:: -del *.obj -del echosk.* echo.hh -del *.exe sysprop.hh syspropsk.cc: sysprop.idl $(top)/bin/x86_win32/omniidl -t -bcxx -wbh=.hh -wbs=sk.cc -wbtp sysprop.idl |
3.6.3. 编译文件
nmake -f dircc.mak
3.6.4. 测试
在第5控制台
syspropcc java.home,测试结果如下所示
| d:/mywork/t1>syspropcc java.home java.home=d:/bea/jdk130/jre |
4. 小结
另还使用了j2sdkee1.2.1进行测试,由于j2sdkee1.2.1起动时的nameserver的port是1050所以启动服务要加参数,对于本文中的程序运行时要如下所示:
java syspropserver -orbinitialport 1050
如果用ior的方式,也可以用omni的omninames.exe程序做命名服务器,用c++编写服务器,客户机使用java和c++编写,c++编写服务器的例子可见omni的文档。
本次只是简单进行了测试,可以使大家了解一下,corba的这种特性,多种不同程序语言进行协作编程的具体运作过程,希望可以抛砖引玉。
闽公网安备 35060202000074号