服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

亲身体验corba: 使用java和c++混合编程

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.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.*;
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:/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 [环境变量名]" << 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)/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的这种特性,多种不同程序语言进行协作编程的具体运作过程,希望可以抛砖引玉。

扫描关注微信公众号