一、CORBA组成
CORBA(Common Object Request Broker Architecture)即公共对象请求代理体系结构。它是由 OMG (Object Management Group)即对象管理组织制订的一种标准的面向对象应用程序体系规范。由对象请求代理 ORB、对象服务、公共设施、域接口和应用接口这几个部分组成。其核心部分是对象请求代理 ORB (Object Request Broker)。ORB 提供了一种机制,通过这种机制,对象可以透明的发出请求和接收响应。ORB可看作是在对象之间建立客户/服务关系的一种中间件。ORB截取客户发送的请求,并负责在该软件总线上找到实现该请求的服务对象,然后完成参数、方法调用,并返回最终结果。
二、CORBA 体系结构
三、CORBA工作流程
首先使用 IDL定义对象和方法,然后 Client 调用定义的对象方法,该调用被ORB传递到Server,接着 Server真正调用该方法,最后结果沿原路返回。
1. Server启动,等待来自 Client 的请求
Server启动后,它首先生成一个 POA(potable object adapter)。然后告诉 POA他所能提供的服务,即 Servant(Server按照 IDL定义所实现的每个对象)。Server从POA处得到每个 Servant 的引用OR(Object Reference)。Server把自己提供的服务公布出来,这里有两个方法:将OR 转换为一个字符串并输出(
notes:可互操作对象引用 (IOR), 是一个数据结构,它提供了关于类型、协议支持和可用 ORB 服务的信息。ORB 创建、使用并维护该 IOR.);将这个 OR绑定到一个简单易理解的名字上,这通过 Naming Service 完成。
2. Client 调用定义的对象方法
Client 通过Naming Service查询获得要访问的对象的引用 OR(object reference),或通过一个字符串获得;Client 通过这个引用调用对象的方法,因为
OR 中有足够的信息来定位一个对象,然后这个调用被传递给 ORB。
四、 CORBA编程的基本概念
- 对象请求代理ORB(Object Request Broker)
- 接口定义语言IDL(Interface Defination Language)
- 对象的引用(Object Reference)唯一定位分布的对象,是一个字符串。
- 客户程序(Client)可以直接使用对象引用定位、访问活动的服务对象。
- 命名服务(Naming Service)是定位分布对象的最佳手段,命名服务负责将对象的逻辑名解析为该对象的引用字符串,称为名字解析(Name resolving),可以联系主机域名和DNS服务器来理解。
- 服务程序(Servant)将服务对象注册到命名服务器并和一个逻辑名绑定,客户程序可以从命名服务器获得该服务对象逻辑名的对象引用字符串。
- 对象逻辑名由名字组件(Name compoment)组成,名字组件由ID、Kind两个域组成。
- 名字上下文(Name context)中包含对象逻辑名绑定的集合,同时一个名字上下文也可绑定到另一个名字上下文中,则对象逻辑名的绑定包括两类:对普通对象名的绑定和对一个名字上下文的绑定。
- POA是服务程序与ORB(Object Request Broker)之间的媒介,提供对对象的管理、适配和Object Key的分配。
五、编程环境配置
进行CORBA开发,需要选择一个ORB和一种熟悉的编程语言,对于学习者而言,omniORBpy和Python就是一对很好的组合。
1. Python简介
Python是面向对象的脚本开发语言,语法非常精简,容易上手。
2. 配置omniORBpy的开发环境
操作系统是Windows:
1、安装Python解释环境
a)到
http://www.activestate.com 下载ActivePython2.4;
b)安装到C:\Python24目录下即可;
2、安装omniORBpy
a)到
http://omniorb.sourceforge.net下载omniORBpy2.6,选择下载已经使用VC++编译好的二进制版本(如果使用C++编程则下载omniORB);
b)从源代码编译omniORBpy时,需要omniORB的C++库,则还需要下载omniORB的源代码,操作系统上也要有VC++的编译环境;
c)下载完后解压到C:\omniORBpy目录下;
3、配置环境变量
a)首先将C:\omniORBpy\bin\x86_win32目录添加到环境变量PATH中,这样在命令行下就可以直接运行omniORBpy提供的命令,如用于编译IDL文件的omniidl和提供命名服务的omninames等;
b)PYTHONPATH变量是Python搜索模块的路径集合,将C:\ominiORBpy\lib\python和C:\omniORBpy\lib\x86_win32添加到PYTHONPATH中,使得Python可以搜索到omniORBpy提供的CORBA编程模块;
c)omniORB首先会读OMNIORB_CONF环境变量找配置文件,如果未设置该环境变量则到注册表的”HKEY_LOCAL_MACHINE/Software/omniORB”位置下读取相关配置信息;
d)“我的电脑-属性-高级-环境变量”中可以编辑环境变量;
4、配置命名服务器
若程序要用到命名服务,则可在创建命名服务对象时指定命名服务器的地址,也可以在注册表中添加。例如要使用本地的命名服务器“NameService”,则在HKEY_LOCAL_MACHINE/Software/omniORB/下创建名为“InitRef”,类型为字符串,值为“NameService=corbaname::localhost”的子键,在后面的例子中会看到如何使用命名服务绑定和解析对象逻辑名。
六、CORBA编程基本步骤
1、编写IDL接口描述文件;
2、将IDL编译成所用开发语言的库,如C++、Java、Python,omniORBpy用于编译IDL的命令为omniidl;
3、配置并启动Naming Service(可选),omniORBpy命名服务的命令为omninames;
4、编写服务程序,在命名服务器上绑定对象IOR的逻辑名;
5、编写客户程序,访问命名服务器解析对象逻辑名的IOR;
七、omniORBpy编程实例
还是从最简单的打印“Hello, World!”开始吧。设当前工作目录为:C:\omniORBpy\scripts\messenger。
1、编写IDL接口定义文件
---bof:secret_messenger.idl---
module messenger
{
interface SecretMessage
{
string getMessage();
};
};
---eof---
2、 使用omniidl命令将IDL文件编译成Python模块
omniidl –bpython secret_messenger.idl
Notes:编译成功后将生成包括客户程序(Client)使用的Stubs(接口存根)和服务程序(Servant)使用的Skeleton(接口框架),客户程序使用的Stubs在messenger文件夹中,服务程序使用的Skeleton在messenger__POA文件夹中。在Step1的IDL中定义了一个仅包含一个方法的SecretMessage接口,遵照OMG组织发布的Python的映射规范-IDL中定义的接口将被映射到Python的若干类中,生成secret_messenger_idl.py文件, 其py文件编译后则生成secret_messenger_idl.pyc文件。
3、 使用IOR定位对象编写CORBA服务程序
(1)、Servant需要以Skeleton中的框架类为父类,定义包括了具体实现的服务类,并创建服务对象的实例。
(2)、再向Servant端的ORB注册(发布)该对象,联系基本概念中对POA的描述-POA是Servant与ORB之间管理Object的媒介,向ORB注册、激活对象需要用到POA对象。则首先要创建并初始化ORB对象请求代理和POA(Portable ObjectAdaptor),使用POAManager对象向ORB服务注册并激活SecretMessage对象。POA对服务程序而言非常重要,它是用于管理服务程序中所有可用对象的那个对象(在面向对象的程序设计中一切都是对象,除此之外没有别的),每个POA对象拥有自己的POA Manager,用于管理所有注册的对象。
(3)、创建了服务对象实例,启动ORB服务组件,获取了RootPOAManager,接下来就要向ORB激活对象实例,激活的方法OurSecretMessage类已经从messenger__POA.SecretMessage类中继承获得,即_this()方法。本例中将服务对象的IOR字符串值写入message.ior文件中,我们可以通过Email的方式将IDL文件和message.ior文件发布给客户程序开发者。
---bof:messenger_server.py---
#!C:\Python24\python.exe
#windows下首行,inux环境下首行使用#!/usr/bin/env python
#Import the sys module to access sys.argvimport sys
#Import omniORB’s implementations of the CORBA and PortableServer modulesfrom omniORB import CORBA, PortableServer
#Import the client-side stubs and server-side skeletons
import messenger, messenger__POA
# Servant class definition,define an implementation class, which derives from the skeleton class
class OurSecretMessage(messenger__POA.SecretMessage):
def getMessage(self):
return 'Hello world'
#Initialise the ORB and find the root POA
orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references(“RootPOA”)
# Activate the POA
poa._get_the_POAManager().activate()
# Create an instance and OurSecretMessage a SecretMessage object referenceourMessage = OurSecretMessage()
message_obj = OurMessage._this()
#打印IOR
print orb.object_to_string(message_obj)
#将对象引用字符串IOR写入message.ior文件
output_handle = open(“message.ior”, “w”)
string_ior = orb.object_to_string(message_obj)
output_handle.write(string_ior)
output_handle.close()
# Block for ever (or until the ORB is shut down)
orb.run()
---eof---
4、编写客户脚本
从message.ior文件读取服务对象的IOR,将IOR对象化,调用服务对象的方法getMessage(),将得到”Hello, world!”字符串;
---bof:messenger_client.py---
#!C:\Python24\python.exe
import sys
from omniORB import CORBA
import messenger
#初始化ORBorb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
#从message.ior文件读取服务对象的IOR
input_handle = open(“message.ior”, “r”)
ior = input_handle.read()
input_handle.close()
#从IOR获取对象,导入到自己地址空间中
obj = orb.string_to_object(ior)
mo = obj._narrow(messenger.SecretMessage)
result = mo.getMessage()
print result
---eof---
5、运行情况
(1)、启动服务程序
..\>messenger_server.py
(2)、启动客户程序
..\>messenger_client.py
Hello, world!
(3)、在message.ior文件中存储着Servant激活对象的IOR
---bof:message.ior---
IOR:010000002000000049444c3a6d657373656e6765722f5365637265744d6573736167653a312e300001000000000000006400
0000010102000c00000031302e33312e3230302e38005b0d00000e000000fe8db26a4300000d200000000000000002000000000
00000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100
---eof---
现在只要把messenger.idl和meeage.ior文件发布给客户程序的开发者,客户程序可以从网络中任何位置获取这条消息了。
6、使用命名服务定位分布的对象
前面的服务程序将对象的IOR写入文件中发布,这样做很不方便,如当服务对象的IOR改变时就要重新发布IOR。想象一下互联网中域名服务器是怎样工作的:SP申请IP地址和域名,在域名服务器注册域名;用户要访问该域名,首先到域名服务器解析其IP地址,再访问该IP地址;当SP的IP地址改变时只要在域名服务器更新注册的IP地址即可,用户端依然可以使用域名访问。对象逻辑名和CORBA命名服务,就可以类比域名和域名服务器来理解。
(1)、修改messenger_server.py中初始化orb、poa的部分后得到以下服务程序:
---bof:messenger_server.py---
#!C:\Python24\python.exe
import sys
from omniORB import CORBA, PortableServer
import messenger, messenger__POA
class OurSecretMessage(messenger__POA.SecretMessage):
def getMessage(self):
return 'Hello world!'
#初始化ORB、POA、POA_Manager对象
#orb初始化前需要先指定命名服务器地址
#ORB初始化时,会接受命令行中”-ORB”开始的参数,这里指定命名服务器地址。
sys.argv.extend(("-ORBInitRef", "NameService=corbaname::localhost"))
orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references("RootPOA")
poa._get_the_POAManager().activate()
#创建对象实例及引用
our_message = OurSecretMessage()
message_obj = our_message._this()
#初始化命名服务对象
import CosNaming
# Obtain a reference to the root naming context
name_service_obj = orb.resolve_initial_references("NameService")
name_service_root = name_service_obj._narrow(CosNaming.NamingContext)
assert name_service_root is not None, "Failed to narrow to NamingContext."
#将对象绑定到逻辑名"Messenger.SecretMessage"
message_name = [CosNaming.NameComponent("Messenger", "SecretMessage")]
name_service_root.bind(message_name, message_obj)
print "Bound the Message Object to naming service"
print "Server is running"
orb.run()
---eof---
(2)、修改后的客户程序
---bof:messenger_client.py---
#!C:\Python24\python.exe
import sys
from omniORB import CORBA
import CosNaming
import messenger
#初始化客户ORB,指定访问的命名服务器地址
sys.argv.extend(("-ORBInitRef", "NameService=corbaname::localhost"))
orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
#获取命名服务对象,解析服务对象的逻辑名Messenger.SecretMessage
name_service_obj = orb.resolve_initial_references("NameService")
name_service_root = name_service_obj._narrow(CosNaming.NamingContext)
assert name_service_root is not None, "Failed to narrow to NamingContext."
message_name = [CosNaming.NameComponent("Messenger", "SecretMessage")]
message_obj = name_service_root.resolve(message_name)
result = message_obj.getMessage()
print result
---eof---
(3)、运行情况
(a)、首先启动命名服务
C:\>omniNames
omniORB: Warning: the local loop back interface (127.0.0.1) is used asthis server's address. Only clients on this machine can talk to
this server.
Fri Nov 04 09:59:43 2005:
Read log file successfully.
Root context isIOR:010000002b00000049444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f6e746578744578743a312e3000000100000000
0000005c000000010102000a0000003132372e302e302e3100f90a0b0000004e616d65536572766963650002000000000000000800000001000000005454410100
00001c00000001000000010001000100000001000105090101000100000009010100
Checkpointing Phase 1: Prepare.
Checkpointing Phase 2: Commit.
Checkpointing completed.
… …
(b)、启动服务程序,到omninames绑定逻辑名
C:\Python24\Scripts\messenger>secret_message_srv.py
omniORB: Warning: the local loop back interface (127.0.0.1) is used asthis server's address. Only clients on this machine can talk to
this server.
Bound the Message Object to naming service
Server is running
… …
(c)、启动客户程序,到omninames解析逻辑名
C:\Python24\Scripts\messenger>secret_message_clt.py
Hello, world!