亲身体验CORBA: 使用java和C++混合编程

开发 后端
本文作者通过一次使用SUN的 tnameserv命名服务程序,服务器用JAVA编写,客户机分别用JAVA和C++(VC6+omniORB)编写的试验,希望通过一次编程的具体操作实例来体验或明了CORBA思想。

前  言

现在很多人在对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++编写的客户机分别调用相应的服务

运行环境的设定:

总体环境由jdk1.3+omniORB3.0(www.uk.research.att.com\omniORB\doc\3.0) +vc6 组成,下面说明具体的安装。

2.1. 安装JDK1.3

从SUN公司DOWN JDK1.3或者通过其他方式得到jdk1.3进行安装,再设定相应的环境变量,在本文测试用的电脑上是如下所示:

  1. CLASSPATH=.;  
  2.             JAVA_HOME=D:\jdk130 

修改原来的PATH变量,添加"%JAVA_HOME%\bin;",如下

  1. 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内容如下

  1. set TOP=c:\omni  
  2.             set path=%TOP%\bin\x86_win32;%path%  
  3.             set LIB=%TOP%\bin\x86_win32;%LIB%  
  4.             set INCLUDE=%TOP%\include;%INCLUDE%  
  5.             set VcOsDir=  
  6.             set VSCommonDir

如果你的电脑VC的环境变量已经设定在你的环境变量中,那么C:\Program Files\Microsoft Visual Studio\VC98\Bin\VCVARS32.BAT 就可以不运行。否则运行omni.bat前要首先运行VCVARS32.BAT。

实践过程

约定所有编写的文件保存在D:\mywork\t1中,omni.bat也在这个目录内

3.1. 编写SysProp.idl,功能是返回系统属性

  1. interface SysProp  
  2.             {  string getProperty(in string name);  
  3.             }; 

3.2. 编写JAVA的服务器

3.2.1. 把IDL文件转化为JAVA编程语言代码存根类及helper类。

执行如下命令

  1. idlj -fall SysProp.idl 

在正常的情况下D:\mywork\t1 目录内将生成以下文件,否则请检查你的执行程序及文件

SysProp.java 
SysPropHelper.java 
SysPropHolder.java 
SysPropOperations.java 
_SysPropImplBase.java 
_SysPropStub.java

3.2.2. 编写 SysPropServer.java

  1. import org.omg.CosNaming.*;  
  2.             import org.omg.CORBA.*; 

//编写相对应的服务,一定要从 _类名ImplBase继承,并实现相应的方法 class SysPropS extends _SysPropImplBase //具体的服务实现

  1. {  public String getProperty(String key)  
  2.             {  
  3.             System.out.println("调用"+key);  
  4.             String S;  
  5.             S=System.getProperty(key);  
  6.             if (S==null)   { S="null"; }  
  7.             System.out.println(key+"="+S);  
  8.             return S;  
  9.             }  
  10.             }  
  11.             public class SysPropServer          //起动服务的程序  
  12.             {  public static void main(String args[])  
  13.             {  try 
  14.             {  System.out.println("创建和初始化 ORB ");  
  15.             ORB orb = ORB.init(args, null);  
  16.             System.out.println("创建服务对象并将其向 ORB 注册 ");  
  17.             SysPropS impl = new SysPropS();  
  18.             orb.connect(impl);  
  19.             //打印IOR字符串  
  20.             System.out.println(orb.object_to_string(impl));  
  21.             org.omg.CORBA.Object namingContextObj =orb.resolve_initial_references("NameService");  
  22.                      NamingContext namingContext= NamingContextHelper.narrow(namingContextObj);  
  23.             NameComponent[] path = {new NameComponent("SysProp""")};  
  24.             System.out.println("绑定服务...SysPropS");  
  25.             namingContext.rebind(path, impl);  
  26.             System.out.println("等待调用...SysPropS");  
  27.             java.lang.Object sync = new java.lang.Object();  
  28.             synchronized (sync)  
  29.             {  sync.wait();  
  30.             }  
  31.             }  
  32.             catch (Exception e)  
  33.             {   System.err.println("Error: " + e);  
  34.             e.printStackTrace(System.out);  
  35.             }  
  36.             }  
  37.             } 

3.3. 编写JAVA的客户机

3.3.1. 编写 SysPropClient.java 使用IOR字符串的方式

注意在代码内有一段注解掉的代码,用"//使用ORB的方法的开始"开始,用"//使用ORB的方法的结束"结束。这段代码是使用ORB方法的代码,如果在代码中"//使用IOR的方法开始"前一行添加"/*",在"//使用IOR的方法结束"后一行添加"*/",而把"//使用ORB的方法的开始"前面的"/*"去掉,把"//使用ORB的方法的结束"后面的"*/"去掉,就是使用ORB方法的代码,程序运行时就是" SysPropClient [环境变量] "的方式。以下是具体代码:

  1. import org.omg.CosNaming.*;  
  2.             import org.omg.CORBA.*;  
  3.             public class SysPropClient  
  4.             {  
  5.             public static void main(String args[])  
  6.             {  
  7.             try{  
  8.             String SetInfo,ReturnInfo,ref;  
  9.             org.omg.CORBA.Object objRef;  
  10.             SysProp syspropRef;  
  11.             ORB orb = ORB.init(args, null);  
  12.             //使用IOR的方法开始  
  13.             if (args.length>=1)  
  14.             {  
  15.             ref=args[0];  
  16.             }  
  17.             else 
  18.             {  
  19.             System.out.println("SysPropClient <IOR字符串>  [环境变量]");  
  20.             return;  
  21.             }  
  22.             objRef = orb.string_to_object(ref);  
  23.             syspropRef = SysPropHelper.narrow(objRef);  
  24.             //使用IOR的方法结束  
  25.             /*  
  26.             //使用ORB的方法的开始  
  27.             objRef = orb.resolve_initial_references("NameService");  
  28.             NamingContext ncRef = NamingContextHelper.narrow(objRef);  
  29.             // 进行服务定位  
  30.             NameComponent nc = new NameComponent("SysProp", "");  
  31.             NameComponent path[] = {nc};  
  32.             syspropRef = SysPropHelper.narrow(ncRef.resolve(path));  
  33.             //使用ORB的方法的开始结束  
  34.             */ 
  35.             if (args.length>1)  
  36.             {  
  37.             SetInfo=args[1];  
  38.             }  
  39.             else 
  40.             {  
  41.             SetInfo="java.home";  
  42.             }  
  43.             System.out.println("开始调用");  
  44.             ReturnInfo = syspropRef.getProperty(SetInfo);  
  45.             System.out.println(SetInfo+"="+ReturnInfo);  
  46.             } catch (Exception e) {  
  47.             System.out.println("ERROR : " + e) ;  
  48.             }  
  49.             }  
  50.             } 

3.3.2. 编译程序,在文件目录内执行如下命令

jAVAC *.JAVA

3.4. 进行测试

第1控制台,执行

tnameserv

测试时如下所示

  1. D:\mywork\t1>java tnameserv  
  2.             Initial Naming Context:  
  3.             IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f  
  4.             6e746578743a312e3000000000010000000000000054000101000000000c3139322e3136382e302e  
  5.             31000ca6000000000018afabcafe00000002a999c474000000080000000000000000000000010000  
  6.             0001000000140000000000010020000000000001010000000000  
  7.             TransientNameServer: setting port for initial object references to: 900  
  8.             Ready. 

第2控制台,执行

java SysPropServer

测试时如下所示

  1. D:\mywork\t1>java SysPropServer  
  2.             创建和初始化 ORB  
  3.             创建服务对象并将其向 ORB 注册  
  4.             IOR:000000000000001049444c3a53797350726f703a312e30000000000100000000000000540001  
  5.             01000000000c3139322e3136382e302e31000ca7000000000018afabcafe00000002a999dbeb0000  
  6.             00080000000000000000000000010000000100000014000000000001002000000000000101000000  
  7.             0000  
  8.             绑定服务...SysPropS  
  9.             等待调用...SysPropS 

第3控制台,执行

java SysPropClient IOR:XXX JAVA.HOME

测试时如下所示

  1. D:\mywork\t1>java SysPropClient IOR:000000000000001049444c3a53797350726f703a312e  
  2.             3000000000010000000000000054000101000000000c3139322e3136382e302e31000ca700000000  
  3.             0018afabcafe00000002a999dbeb0000000800000000000000000000000100000001000000140000  
  4.             000000010020000000000001010000000000 java.home  
  5.             开始调用  
  6.             java.home=D:\bea\jdk130\jre  
  7.              

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

  1. #include <iostream.h>  
  2.             #include <SysProp.hh>  
  3.             int main(int argc, char** argv)  
  4.             {  
  5.             try {  
  6.             CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "omniORB3");  
  7.             if( argc < 2 || argc > 3 ) {  
  8.             cout << "usage:  SysPropC <IOR字符串> [环境变量名]" << endl;  
  9.             return 1;  
  10.             }  
  11.             CORBA::Object_var obj = orb->string_to_object(argv[1]);  
  12.             SysProp_ptr echoref = SysProp::_narrow(obj);  
  13.             if( CORBA::is_nil(echoref) ) {  
  14.             cerr << "没有对象" << endl;  
  15.             return 1;  
  16.             }  
  17.             const char* message;  
  18.             if (argc==3)  
  19.             {  
  20.             message=argv[2];  
  21.             }  
  22.             else 
  23.             {  
  24.             message="java.home";  
  25.             }  
  26.             CORBA::String_var dest = echoref->getProperty(message);  
  27.             cout <<  (char*)message << "=" <<(char*)dest << endl;  
  28.             orb->destroy();  
  29.             }  
  30.             catch(...) {  
  31.             cerr << "Caught unknown exception." << endl;  
  32.             }  
  33.             return 0;  
  34.             }  
  35.              

3.5.3. 编写dirc.mak,如下所示

  1. TOP = C:\omni  
  2.             OMNI_DYNAMIC_LIB = msvcstub.lib -NODEFAULTLIB:libcmt.lib -NODEFAULTLIB:libcmtd.lib  
  3.             CORBA_CPPFLAGS = -D__WIN32__ -D__x86__ -D__NT__ -D__OSVERSION__=4 
  4.             CORBA_LIB      = omniORB304_rt.lib omnithread2_rt.lib \  
  5.             $(OMNI_DYNAMIC_LIB) \  
  6.             wsock32.lib advapi32.lib \  
  7.             -libpath:$(TOP)\lib\x86_win32  
  8.             CXXFLAGS       = -O2 -MD -GX $(CORBA_CPPFLAGS) $(DIR_CPPFLAGS)  
  9.             CXXLINKOPTIONS =  
  10.             .SUFFIXES: .cc  
  11.             .cc.obj:  
  12.             cl /nologo /c $(CXXFLAGS) /Tp$<  
  13.             all:: SysPropC.exe  
  14.             SysPropC.exe: SysPropSK.obj SysPropC.obj  
  15.             link -nologo $(CXXLINKOPTIONS) -out:$@ $** $(CORBA_LIB)  
  16.             clean::  
  17.             -del *.obj  
  18.             -del *.exe  
  19.             veryclean::  
  20.             -del *.obj  
  21.             -del echoSK.* echo.hh  
  22.             -del *.exe  
  23.             SysProp.hh SysPropSK.cc: SysProp.idl  
  24.             $(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

本测试如下所示

  1. D:\mywork\t1>syspropc IOR:000000000000001049444c3a53797350726f703a312e3000000000  
  2.             010000000000000054000101000000000c3139322e3136382e302e31000ca7000000000018afabca  
  3.             fe00000002a999dbeb00000008000000000000000000000001000000010000001400000000000100  
  4.             20000000000001010000000000 os.name  
  5.             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编写的服务器及客户机就可以在上面运行。本例子如下所示

  1. Initial Naming Context:  
  2.             IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f  
  3.             6e746578743a312e3000000000010000000000000054000101000000000c3139322e3136382e302e  
  4.             31000ca6000000000018afabcafe00000002a999c474000000080000000000000000000000010000  
  5.             0001000000140000000000010020000000000001010000000000  
  6.             TransientNameServer: setting port for initial object references to: 900  
  7.             Ready. 

那么就要把从 IOR:开始(含IOR:)后面的字符串放进注册表。

3.6.1. 编写SysPropCC.cc

  1. //使用NAME方式的客户机  
  2.             #include <iostream.h> 
  3.             #include "SysProp.hh"  
  4.             static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb);  
  5.             int main (int argc, char **argv)  
  6.             {  
  7.             if(  argc != 2 ) {  
  8.             cout << "使用方法: SysPropCC  <环境变量名><< endl;  
  9.             return 1;  
  10.             }  
  11.             try {  
  12.             CORBA::ORB_var orb = CORBA::ORB_init(argc, argv, "omniORB3");  
  13.             CORBA::Object_var obj = getObjectReference(orb);  
  14.             SysProp_ptr echoref = SysProp::_narrow(obj);  
  15.             const char* message;  
  16.             if (argc==2){message=argv[1];}  
  17.             else {message="java.home"; }  
  18.             CORBA::String_var dest = echoref->getProperty(message);  
  19.             cout <<  (char*)message << "=" <<(char*)dest << endl;  
  20.             orb->destroy();  
  21.             }  
  22.             catch(...) { cerr << "Caught unknown exception." << endl; }  
  23.             return 0;  
  24.             }  
  25.             //////////////////////////////////////////////////////////////////////  
  26.             static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb)  
  27.             {  
  28.             CosNaming::NamingContext_var rootContext;  
  29.             try {  
  30.             // 定位服务器:  
  31.             CORBA::Object_var obj;  
  32.             obj = orb->resolve_initial_references("NameService");  
  33.             // Narrow the reference returned.  
  34.             rootContext = CosNaming::NamingContext::_narrow(obj);  
  35.             if( CORBA::is_nil(rootContext) ) {  
  36.             cerr << " 初始化不成功." << endl;  
  37.             return CORBA::Object::_nil();  
  38.             }  
  39.             }  
  40.             catch(CORBA::ORB::InvalidName& ex) {  
  41.             cerr << " 没有找到服务" << endl;  
  42.             return CORBA::Object::_nil();  
  43.             }  
  44.             CosNaming::Name name;  
  45.             name.length(1);  
  46.             name[0].id   = (const char*) "SysProp";  
  47.             name[0].kind = (const char*) "";  
  48.             try {  
  49.             // Resolve the name to an object reference.  
  50.             return rootContext->resolve(name);  
  51.             }  
  52.             catch(...) {  cerr << "定位不成功." << endl;}  
  53.             return CORBA::Object::_nil();  
  54.             } 

3.6.2. 编写dircc.mak

  1. TOP = C:\omni  
  2.             DIR_CPPFLAGS   = -I. -I$(TOP)\include  
  3.             OMNI_DYNAMIC_LIB = msvcstub.lib -NODEFAULTLIB:libcmt.lib -NODEFAULTLIB:libcmtd.lib  
  4.             CORBA_CPPFLAGS = -D__WIN32__ -D__x86__ -D__NT__ -D__OSVERSION__=4 
  5.             CORBA_LIB      = omniORB304_rt.lib omnithread2_rt.lib \  
  6.             $(OMNI_DYNAMIC_LIB) \  
  7.             wsock32.lib advapi32.lib \  
  8.             -libpath:$(TOP)\lib\x86_win32  
  9.             CXXFLAGS       = -O2 -MD -GX $(CORBA_CPPFLAGS) $(DIR_CPPFLAGS)  
  10.             CXXLINKOPTIONS =  
  11.             .SUFFIXES: .cc  
  12.             .cc.obj:  
  13.             cl /nologo /c $(CXXFLAGS) /Tp$<  
  14.             all:: SysPropCc.exe  
  15.             SysPropCc.exe: SysPropSK.obj SysPropCc.obj  
  16.             link -nologo $(CXXLINKOPTIONS) -out:$@ $** $(CORBA_LIB)  
  17.             clean::  
  18.             -del *.obj  
  19.             -del *.exe  
  20.             veryclean::  
  21.             -del *.obj  
  22.             -del echoSK.* echo.hh  
  23.             -del *.exe  
  24.             SysProp.hh SysPropSK.cc: SysProp.idl  
  25.             $(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,

测试结果如下所示

  1. D:\mywork\t1>syspropcc java.home  
  2.             java.home=D:\bea\jdk130\jre 

小  结

另还使用了j2sdkee1.2.1进行测试,由于j2sdkee1.2.1起动时的nameserver的PORT是1050 所以启动服务要加参数,对于本文中的程序运行时要如下所示:
java SysPropServer -ORBInitialPort 1050

如果用IOR的方式,也可以用omni的omniNames.exe程序做命名服务器,用C++编写服务器,客户机使用Java和C++编写,c++编写服务器的例子可见omni的文档。

本次只是简单进行了测试,可以使大家了解一下,CORBA的这种特性,多种不同程序语言进行协作编程的具体运作过程,希望可以抛砖引玉。

参考资料

《JAVA2核心技术 卷II:高级特性》(对于omniORB是2.0的例子)

《The omniORB version 3.0 User's Guid》(omniORB软件内自带)

原文链接:http://www.cnblogs.com/adylee/archive/2008/11/21/1338629.html

【编辑推荐】

  1. Java线程:线程安全与不安全
  2. Java NIO原理图文分析及代码实现
  3. Java RMI远程调用
  4. 浅谈Java的方法覆盖与变量覆盖
  5. Java类变量和成员变量初始化过程
责任编辑:林师授 来源: 王辉的博客
相关推荐

2009-07-20 09:53:43

Java混合编程

2011-07-01 14:55:28

Qt QML C++

2012-04-28 15:28:21

JNI混合编程Java

2015-06-29 10:05:10

C#异步编程解析

2011-02-15 13:12:02

JavaC++

2012-03-20 11:37:24

JavaJNI

2013-01-22 14:05:25

Fedora 18

2010-09-16 14:36:20

2011-12-29 10:13:48

FirefoxAndroid版

2010-09-17 13:47:35

2011-05-06 17:57:34

思维R800扫描仪

2013-01-22 11:29:01

3D打印

2010-05-06 10:17:58

混合编程Java程序员

2010-01-11 09:40:02

C++语言

2021-07-11 18:04:04

C语言

2011-05-18 18:05:47

C#C++

2011-10-27 18:06:24

思科网真

2010-01-18 17:14:50

C++语言

2011-05-30 15:29:32

C++

2009-11-26 14:10:08

点赞
收藏

51CTO技术栈公众号