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

来源:互联网 发布:广东网络教育学费多少 编辑:程序博客网 时间:2024/05/10 03:20

1.   前言 



  现在很多人在对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.comomniORBdoc3.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 FilesMicrosoft Visual Studio



  2.3.   安装omniORB



  从 
http://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:omniREADME.win32 文档进行设定,由于运行程序及命令行在控制台进行,所以本次测试并不根据文档要求去设定环境变量,而是编写了一个omni.bat,在使用控制台时,首先运行。



  本测试电脑omni.bat内容如下







set TOP=c:omni



set path=%TOP%binx86_win32;%path%

set LIB=%TOP%binx86_win32;%LIB%

set INCLUDE=%TOP%include;%INCLUDE%

set VcOsDir=

set VSCommonDir= 









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



 3.   实践过程



  约定所有编写的文件保存在D:myworkt1中,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:myworkt1 目录内将生成以下文件,否则请检查你的执行程序及文件



  SysProp.java



  SysPropHelper.java



  SysPropHolder.java



  SysPropOperations.java



  _SysPropImplBase.java



  _SysPropStub.java



  3.2.2.   编写 SysPropServer.java 





import org.omg.CosNaming.*;



import org.omg.CORBA.*; 









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

  class SysPropS extends _SysPropImplBase   //具体的服务实现





{ public String getProperty(String key) 





System.out.println("调用"+key);



String S;



S=System.getProperty(key);



if (S==null) { S="null"; }



System.out.println(key+"="+S);



return S;



}



}



public class SysPropServer //起动服务的程序



{ public static void main(String args[])



{ try



{ System.out.println("创建和初始化 ORB ");



ORB orb = ORB.init(args, null);



System.out.println("创建服务对象并将其向 ORB 注册 ");



SysPropS impl = new SysPropS();



orb.connect(impl);



//打印IOR字符串



System.out.println(orb.object_to_string(impl));



org.omg.CORBA.Object namingContextObj =orb.resolve_initial_references("NameService");



NamingContext namingContext= NamingContextHelper.narrow(namingContextObj);



NameComponent[] path = {new NameComponent("SysProp", "")};



System.out.println("绑定服务...SysPropS");



namingContext.rebind(path, impl);



System.out.println("等待调用...SysPropS");



java.lang.Object sync = new java.lang.Object();



synchronized (sync)



{ sync.wait();



}



}



catch (Exception e)



{ System.err.println("Error: " + e);



e.printStackTrace(System.out);



}



}









  3.3.   编写JAVA的客户机 



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



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







import org.omg.CosNaming.*;

import org.omg.CORBA.*;

public class SysPropClient 

{

   public static void main(String args[])

   {

  try{

    String SetInfo,ReturnInfo,ref;

    org.omg.CORBA.Object objRef;

      SysProp syspropRef;

    ORB orb = ORB.init(args, null);

//使用IOR的方法开始

          if (args.length>=1)

          {

            ref=args[0];

          }

          else

             {

             System.out.println("SysPropClient [环境变量]");

          return;

          }

       objRef = orb.string_to_object(ref);

syspropRef = SysPropHelper.narrow(objRef);

//使用IOR的方法结束

/*

//使用ORB的方法的开始

        objRef = orb.resolve_initial_references("NameService");

         NamingContext ncRef = NamingContextHelper.narrow(objRef);

         // 进行服务定位

         NameComponent nc = new NameComponent("SysProp", "");

         NameComponent path[] = {nc};

syspropRef = SysPropHelper.narrow(ncRef.resolve(path));

//使用ORB的方法的开始结束

*/

       if (args.length>1)

         {

         SetInfo=args[1];

         }

         else

         {

         SetInfo="java.home";

         }

        System.out.println("开始调用");

        ReturnInfo = syspropRef.getProperty(SetInfo);

        System.out.println(SetInfo+"="+ReturnInfo);

  } catch (Exception e) {

     System.out.println("ERROR : " + e) ;

  }

   }











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



  jAVAC *.JAVA



  3.4.   进行测试



  第1控制台,执行



  tnameserv



  测试时如下所示





D:myworkt1>java tnameserv

Initial Naming Context:

IOR:000000000000002849444c3a6f6d672e6f726

72f436f734e616d696e672f4e616d696e67436f6e7

46578743a312e30000000000100000000000000

54000101000000000c3139322e3136382e302e3

1000ca6000000000018afabcafe00000002a999c

474000000080000000000000000000000010000

00010000001400000000000100200000
0000001

010000000000

TransientNameServer: setting port for initial object references to: 900

Ready. 









  第2控制台,执行



  java SysPropServer



  测试时如下所示 





D:myworkt1>java SysPropServer 

创建和初始化 ORB



创建服务对象并将其向 ORB 注册



IOR:000000000000001049444c3a5379735

0726f703a312e3000000000010000000000

000054000101000000000c3139322e3136

382e302e31000ca7000000000018afabcaf

e00000002a999dbeb00000008000000000

0000000000000010000000100000014000

0000000010020000000000001010000000

000



绑定服务...SysPropS



等待调用...SysPropS









  第3控制台,执行 



  java SysPropClient IOR:XXX JAVA.HOME



  测试时如下所示 





D:myworkt1>java SysPropClient IOR:000000000000001049444c3a5379735

0726f703a312e3000000000010000000000

000054000101000000000c3139322e3136

382e302e31000ca7000000000018afabcaf

e00000002a999dbeb00000008000000000

0000000000000010000000100000014000

0000000010020000000000001010000000000

java.home



开始调用



java.home=D:beajdk130jre

 3.5.   编写C++的IOR客户机



  从实践来讲编写C++的客户机程序同JAVA没有多大的区别,只不过JAVA是用idlj生成代码存根类及helper类,而omni是用omniidl来生成代码存根类及helper类,而编程思想及编码过程非常相似。



  由于C++的程序要调用omni及VC6的相关文件,所以进入控制台后,如果VC没有进行环境变量设定,那么要先运行C:Program FilesMicrosoft Visual StudioVC98BinVCVARS32.BAT,再运行omni.bat,否则直接运行omni.bat后再编译程序及运行程序。



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



  执行如下命令



  omniidl -bcxx SysProp.idl 



  在正常的情况下D:myworkt1 目录内将生成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 [环境变量名]" << endl;



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)libx86_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)binx86_win32omniidl -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:myworkt1>syspropc IOR:000000000000001049444c3a53797350726f70

3a312e30000000000100000000000000540001010

00000000c3139322e3136382e302e31000ca70000

00000018afabcafe00000002a999dbeb0000000800

00000000000000000000010000000100000014000

0000000010020000000000001010000000000

os.name

os.name=Windows 2000 









  3.6.   编写C++的NAME方式客户机



  为了使用NANE方式,必须为OMNI软件设置注册表信息,要在注册表中建立如下数据项(regedit)HKEY_LOCAL_MACHINESOFTWAREORLomniORB2.0NAMESERVICE(字符串)。



  NAMESERVICE的值为tnameserv(jdk1.3bin内的程序)启动的IOR值(第一次设置时自行添加)。



  注意为了使用这种方式每次起动tnameserv后要用新IOR值换去旧的IOR值,我测试过用omini的omniNames.exe程序做服务器,IOR值是不变的,但服务器用JVAV编写就会出错。如果起动tnameserv,用 c编写的服务器及客户机就可以在上面运行。本例子如下所示 





Initial Naming Context:

IOR:000000000000002849444c3a6f6d672e6f72672f43

6f734e616d696e672f4e616d696e67436f6e746578743a

312e30000000000100000000000000540001010000000

00c3139322e3136382e302e31000ca6000000000018af

abcafe00000002a999c47400000008000000000000000

000000001000000010000001400000000000100200000

00000001010000000000

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)libx86_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)binx86_win32omniidl -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:myworkt1>syspropcc java.home

java.home=D:beajdk130jre 









  4.   小结



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



  java SysPropServer -ORBInitialPort 1050 



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



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

原创粉丝点击