CORBA
公用对象请求代理(调度)程序体系结构(Common Object Request Broker Architecture),缩写为 CORBA,是对象管理组织(Object Management Group)对应当今快速增长的软硬件的协同工作能力的要求而提出的方案。简而言之,CORBA 允许应用程序和其他的应用程序通讯,而不论他们在什么地方或者由谁来设计。
CORBA曾经是分布式计算的主流技术,在电信等领域使用广泛。开发和部署成本较高,目前属于已经基本被遗弃的技术,被轻量级的Web服务、RESTful服务等代替了。
ORB(Object Request Broker)
对象请求代理。ORB 是一个中间件,他在对象间建立客户-服务器的关系。通过 ORB,一个客户可以很简单地使用服务器对象的方法而不论服务器是在同一机器上还是通过一个网络访问。ORB 截获调用然后负责找到一个对象实现这个请求,传递参数和方法,最后返回结果。客户不用知道对象在哪里,是什么语言实现的,他的操作系统以及其他和对象接口无关的东西。
IDL
IDL全称接口定义语言,是用来描述软件组件接口的一种规范语言。用户可以定义模块、接口、属性、方法、输入输出参数,甚至异常等等。IDL在不同的语言下都有相应的实现,可以把IDL描述的接口编译为目标语言,包括客户端代理和服务器端框架,以及相应的帮助类等等。比如Java中提供过了idlj命令用来编译。
CORBA与ORB的关系
CORBA的分布式对象调用能力依赖于ORB,而ORB之间进行通信是通过GIOP协议完成的。GIOP定义了ORB之间互操作的传输语法和标准消息格式,比如请求头、请求体所包含的字段和长度。
下面是IDL和java编程:
原文:https://www.cnblogs.com/redsun1015/archive/2016/09/23/5899791.html
IDL用中立语言的方式进行描述,能使软件组建(不同语言编写的)间相互通信。
IDL提供了一个桥来连接不同的系统。
Corba 上的服务用IDL描述,将被映射为某种程序设计语言。并且分为两部分,在客户方叫IDL stub,在服务器方叫IDL skeleton,两者可以采用不同的语言。而双方又要通过ORB 对象请求代理总线通信。
常用的数据类型:
1数据类型
(1)基本数据类型:OMG IDL基本数据类型包括short,long和相应的无符号(unsigned)类型,表示的字长分别为16,32位。
(2)浮点数类型:OMG IDL浮点数类型包括float,double和long double类型。其中float表示单精度浮点数,double表示双精度浮点数,long double表示扩展的双精度浮点数。
(3)字符和超大字符类型:OMG IDL 定义字符类型char为面向字节的码集编码的单字节字符,定义类型wchar为从任意字符集中编码的超大字符。
(4)逻辑类型:用boolean关键字定义的一个变量,取值只有true和false。
(5)八进制类型:用octet关键字定义,在网络传输中不进行高低位转换的位元序列。
(6)any数据类型:引入该类型用于表示OMG IDL中任意数据类型。
2 常量
OMG IDL用const关键字声明一个常量,用于模块(module)或接口(interface)中定义保持不变的量,如:
const double PI=3.1415926;
在IDL中,可以定义long,unsigned long,unsigned short,char,boolean,float,double,string类型的常量。
3构造数据类型
类似于C和C++的语法规则,OMG IDL中构造数据类型包括结构、联合、枚举等形式。
如下列:
(1)结构类型:
typedef long GoodsNumber;
struct{GoodsNumber;string name;float price}
(2)联合类型:
union stockIn switch(short){
case 1: stocker:long;
case 2: goodsName1:string;
case 3: goodsName2:string;
}
(3)枚举类型:
enum GoodsStatus{GOODS_SALED,GOODS_INSTOCK};
4数组类型
OMG IDL的数组类型提供了多维定长、统一数据格式的数据存储方式——————数组。没一维的长度必须在定义时给定,所有数据单元必须存储相同类型的元素。
如下例,定义一个长度为20×100的证书数组:
typedef long aDimension[20][100];
5 模板(template)类型
OMG IDL提供两种类型的模板:
(1)序列(sequence)类型:
用该方法定义长度可变的任意数值类型的存储序列,通常在定义时可以指定长度,也可以不指定,如:
typedef sequence<long,80> aSequence;//长度定义为80
typedef sequence anotherSequence;//长度不定
(2)字符串(string)序列:
同样对于字符串序列类型,也有两种定义方式:
typedef string<80> aName;//长度定义为80
typedef string anotherName;//长度不定
- OMG IDL文件举例
module Compute
{ typedef double radius;
typedef long times;
interface PI
{ double getResult( in radiusaRadius, in times time); }
}
上述接口定义文件主要用于客户端向服务对象提出请求:计算π值。因此,模块中定义了一个方法getResult(),以圆的直径(aRadius)和迭代次数(times)作为该方法的输入参数。
- OMG IDL词法规则
OMG IDL采用ASCII字符集构成接口定义的所有标识符。标识符由字母、数字和下划线的任意组合构成,但第一个字符必须是ASCII字母。IDL认为大写字母和小写字母具有相同的含义,例如anExample和AnExample是相同的。
与C++和Java类似,采用以“/”开始,以“/”结束来注释一段代码,以“//”开始注释从“//”开始直至行尾的所有内容。
另外,IDL保留了47个关键字,程序设计人员不能将关键字用作变量或方法名。需要注意的是关键字的大小写,例如:
typedef double context;
//错误:定义的变量context是关键字
typedef double CONTEXT;
//错误:CONTEXT与关键字context冲突
- 数据类型
(1)基本数据类型:OMG IDL基本数据类型包括short、long和相应的无符号(unsigned)类型,表示的字长分别为16、32位。
(2)浮点数类型:OMG IDL浮点数类型包括float、double和longdouble类型。其中float表示单精度浮点数,double表示双精度浮点数,long double表示扩展的双精度浮点数。
(3)字符和超大字符类型:OMG IDL定义字符类型char为面向字节的码集中编码的单字节字符; 定义类型wchar为从任意字符集中编码的超大字符。
(4)逻辑类型:用boolean关键字定义的一个变量,取值只有true和false。
(5)八进制类型:用octet关键字定义,在网络传输过程中不进行高低位转换的位元序列。
(6)any数据类型:引入该类型用于表示OMG IDL中任意数据类型。
- 常量
OMG IDL用const关键字声明一个常量,用于模块(module)或接口(interface)中定义保持不变的量,如:
const double PI = 3.1415926;
在IDL中,可以定义long、unsigned long、unsigned short、char、boolean、float、double、string类型的常量。
- 构造数据类型
类似于C和C++的语法规则,OMG IDL中构造数据类型包括结构、联合、枚举等形式。如下例:
(1)结构类型:
typedef long GoodsNumber;
struct
{ GoodsNumber number;
string name;
float price; }
(2)联合类型:
union stockIn switch( short )
{ case 1: stocker : long;
case 2: goodsName1 : string;
case 3: goodsName2 : string; }
(3)枚举类型:
enum GoodsStatus { GOODS_SALED,GOODS_INSTOCK};
- 数组类型
OMG IDL的数组类型提供了多维定长、统一数据格式的数据存储方式——数组。每一维的长度必须在定义时给定,所有数据单元必须存储相同类型的元素。如下例定义一个长度为20×100的整数数组:
typedef long aDimension[20][100];
7.模板(template)类型
OMG IDL提供两种类型的模板:
(1) 序列(sequence)类型:
用该方法定义长度可变的任意数值类型的存储序列,通常在定义时可以指定长度,也可以不指定,如:
typedef sequence <long,80> aSequence;
//长度定义为80
typedef sequence anotherSequence;
//长度不定
(2) 字符串(string)序列:
同样对于字符串序列类型,也有两种定义方式:
typedef string <80> aName;//长度定义为80
typedef string anotherName; //长度不定
8.接口(interface)
在前几讲中,均提到了CORBA接口,接口作为服务对象功能的详细描述,封装了服务对象提供服务方法的全部信息,客户对象利用该接口获取服务对象的属性、访问服务对象中的方法。
接口用关键字interface声明,其中包含的属性和方法对所有提出服务请求的客户对象是公开的,如下例:
interface JobManager
{ readonly attribute stringFirstName;
attribute string status;
string QueryJobStatus( in longNumber, out string property); }
使用CORBA开发的小例子
如果想开发一个CORBA的Helloworld,基本上有以下几个步骤:
1.使用idl语言开发idl文件,这个文件中描述了接口的定义
module helloworld{
interface HelloWorld{
string sayHello();
};
};
module:对应了java中的package
interface:对应了java中的interface,HelloWorld即接口名称
sayHello:对应了java中interface声明的方法
string:对应了java中方法的返回值
2.使用java中的idlj命令,将idl语言翻译成java语言,并生成java代码
将idl文件拷贝到%JAVA_HOME%\bin下,然后在命令行下切换到bin目录下执行:
idlj -fall helloworld.idl
idlj:java自带的工具
-fall:生成server和client端代码,也可以单独生成server或client
helloworld.idl:之前创建的idl文件
此时,在bin目录下就会生成helloworld文件夹,文件夹中会有6个文件,将这6个拷回eclipse工程中。注意:文件中的包名就是idl中生命的helloworld。如下图:
这时_HelloWorldStub.java、HelloWorld.java、HelloWorldHelper.java、 HelloWorldHolder.java、HelloWorldOperations.java是client需要的代 码;HelloWorld.java、HelloWorldOperations.java、HelloWorldPOA.java是server需要的 代码。
简单看一下自动生成的这几个文件:
HelloWorld.java,与idl中的接口名一模一样,但是实际上只是一个标识接口没有任何的实现
复制代码
package helloworld;
/**
* helloworld/HelloWorld.java .
* Generated by the IDL-to-Java compiler (portable), version "3.2"
* from helloworld.idl
* Friday, May 16, 2014 2:13:26 PM CST
*/
public interface HelloWorld extends HelloWorldOperations, org.omg.CORBA.Object, org.omg.CORBA.portable.IDLEntity
{
} // interface HelloWorld
复制代码
HelloWorldOperations.java,是idl中声明的接口
复制代码
package helloworld;
/**
- helloworld/HelloWorldOperations.java .
- Generated by the IDL-to-Java compiler (portable), version “3.2”
- from helloworld.idl
- Friday, May 16, 2014 2:13:26 PM CST
*/
public interface HelloWorldOperations
{
String sayHello ();
} // interface HelloWorldOperations
复制代码
HelloWorldStub.java、HelloWorldHelper.java、HelloWorldHolder.java是client的桩和工具类;HelloWorldPOA.java是server的实现接口的类(大概是这个意思吧,不太懂),看着比较晕,就不贴了。
3.开发server端的代码
既然开发了接口定义,也翻译成了java代码,那么就要写接口的实现了,实现是在server端的,需要继承自的HelloWorldPOA
复制代码
package server;
import helloworld.HelloWorldPOA;
/**
* 服务器端的实现代码
*
*/
public class HelloWorldImpl extends HelloWorldPOA {
@Override
public String sayHello() {
return "Hello World!";
}
}
复制代码
server启动的代码,这段代码主要功能是将接口实现注册到ORB中,并启动监听,等待client来调用
复制代码
package server;
import helloworld.HelloWorld;
import helloworld.HelloWorldHelper;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.PortableServer.POA;
import org.omg.PortableServer.POAHelper;
import org.omg.PortableServer.POAManagerPackage.AdapterInactive;
import org.omg.PortableServer.POAPackage.ServantNotActive;
import org.omg.PortableServer.POAPackage.WrongPolicy;
public class HelloServer {
public static void main(String[] args) throws ServantNotActive, WrongPolicy, InvalidName, AdapterInactive, org.omg.CosNaming.NamingContextPackage.InvalidName, NotFound, CannotProceed {
//指定ORB的端口号 -ORBInitialPort 1050
args = new String[2];
args[0] = "-ORBInitialPort";
args[1] = "1050";
//创建一个ORB实例
ORB orb = ORB.init(args, null);
//拿到RootPOA的引用,并激活POAManager,相当于启动了server
org.omg.CORBA.Object obj=orb.resolve_initial_references("RootPOA");
POA rootpoa = POAHelper.narrow(obj);
rootpoa.the_POAManager().activate();
//创建一个HelloWorldImpl实例
HelloWorldImpl helloImpl = new HelloWorldImpl();
//从服务中得到对象的引用,并注册到服务中
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
HelloWorld href = HelloWorldHelper.narrow(ref);
//得到一个根名称的上下文
org.omg.CORBA.Object objRef = orb.resolve_initial_references("NameService");
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);
//在命名上下文中绑定这个对象
String name = "Hello";
NameComponent path[] = ncRef.to_name(name);
ncRef.rebind(path, href);
//启动线程服务,等待客户端调用
orb.run();
System.out.println("server startup...");
}
}
复制代码
4.开发client端的代码
server端的实现与服务监听都已经做完,现在需要写一个client来调用server的方法
复制代码
package client;
import helloworld.HelloWorld;
import helloworld.HelloWorldHelper;
import org.omg.CORBA.ORB;
import org.omg.CORBA.ORBPackage.InvalidName;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.NotFound;
public class HelloClient {
static HelloWorld helloWorldImpl;
static {
System.out.println("client开始连接server.......");
//初始化ip和端口号,-ORBInitialHost 127.0.0.1 -ORBInitialPort 1050
String args[] = new String[4];
args[0] = "-ORBInitialHost";
//server端的IP地址,在HelloServer中定义的
args[1] = "127.0.0.1";
args[2] = "-ORBInitialPort";
//server端的端口,在HelloServer中定义的
args[3] = "1050";
//创建一个ORB实例
ORB orb = ORB.init(args, null);
// 获取根名称上下文
org.omg.CORBA.Object objRef = null;
try {
objRef = orb.resolve_initial_references("NameService");
} catch (InvalidName e) {
e.printStackTrace();
}
NamingContextExt neRef = NamingContextExtHelper.narrow(objRef);
String name = "Hello";
try {
//通过ORB拿到了server实例化好的实现类
helloWorldImpl = HelloWorldHelper.narrow(neRef.resolve_str(name));
} catch (NotFound e) {
e.printStackTrace();
} catch (CannotProceed e) {
e.printStackTrace();
} catch (org.omg.CosNaming.NamingContextPackage.InvalidName e) {
e.printStackTrace();
}
System.out.println("client connected server.......");
}
public static void main(String args[]) throws Exception {
sayHello();
}
//调用实现类的方法
public static void sayHello() {
String str = helloWorldImpl.sayHello();
System.out.println(str);
}
}
复制代码
我们可以看到在server和client个创建了一个ORB的实例,这时因为在server和client都需要有支持通信(见上面的CORBA基本结构图)。
5.启动orbd服务
仅仅创建了server和client的代码还不足以跑起来一个HelloWorld,还需要启动一个orbd服务,这个服务在%JAVA_HOME%\jre\bin下。orbd包含自启动服务、透明的命名服务、持久化命名服务和命名管理器的后台处理进程。应该是上面的HelloWorld用到了nameService所以才会需要这个服务,使用其他方式拿server的实例是不是就不需要这个服务了,又或者是所有的CORBA都要与这个服务通信,不太明白?
在命令行下输入启动orbd:
cd /d %JAVA_HOME%\bin
orbd -ORBInitialPort 1050 -ORBInitialHost 127.0.0.1
6.启动server服务
7.启动client
可以看到输出结果:
client开始连接server.......
client connected server.......
Hello World!