xfocus logo xfocus title
首页 焦点原创 安全文摘 安全工具 安全漏洞 焦点项目 焦点论坛 关于我们
添加文章 Xcon English Version

使用omniORBpy开发简单CORBA程序


创建时间:2005-11-04 更新时间:2005-11-05
文章属性:原创
文章提交:r00t (shanleiguang_at_gmail.com)

CORBA被认为是企业级应用采取的技术,但发展到现在已经存在许多开源的CORBA软件,如Linux操作系统的桌面管理系统Gnome就是使用开源的ORBit开发。本文将介绍如何使用omniORBpy 和Python脚本语言来开发简单的CORBA程序,希望对大家理解和掌握CORBA技术有所帮助。

>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的分配。

>omniORBpy简介

工欲善其事、必先厉其器,进行CORBA开发你需要选择一个ORB和一种熟悉的编程语言,对于学习者而言,omniORBpy和Python就是一对很好的组合。omniORB的官方网站(http://omniorb.sourceforge.net)上是这样介绍omniORB的:omniORB is a robust high performance CORBA ORB for C++ and Python. It is freely available under the terms of the GNU Lesser General Public License (for the libraries), and GNU General Public License (for the tools).

>Python简介

事实上我个人偏爱Perl这只“骆驼”-Perl在网络编程、文本解析和数据库处理方面的表现非常出色,可惜它对CORBA的支持一直做的不够好。Python这条“蟒蛇”在国外很流行,据说Yahoo是靠Perl起家、而Google则是靠的Python。Python是面向对象的脚本开发语言,语法非常精简,容易上手。

>配置omniORBpy的开发环境

操作系统是Windows XP SP2,这样我就可以方便的一边调试这些脚本、一边编辑这篇文档,当然顺便再来点Music。

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编程实例

设工作目录%WORKDIR%为C:\omniORBpy\scripts\messenger。

>>Example One:使用对象引用字符串定位对象

Step1.编写IDL接口定义文件

---bof:secret_messenger.idl---
Module messenger
{
    Interface SecretMessage
    {
        String get_message();
};
};
---eof---

Step2.使用omniidl命令将IDL文件编译成Python模块

生成包括客户程序(Client)使用的Stubs(存根?)和服务程序(Servant)使用的Skeleton(骨架?),在Step1中定义了一个仅包含一个方法的SecretMessage接口,遵照OMG组织发布的Python的映射规范-IDL中定义的接口将被映射到Python的若干类中。
secret_messenger_idl.pyc,客户程序使用的Stubs在messenger文件夹中,服务程序使用的Skeleton在messenger__POA文件夹中,这样做的好处在于当接口扩展时便于扩展模块。
%WorkDir%>omniidl –bpython secret_messenger.idl

Step3.编写CORBA服务程序
(1)、Servant需要以Skeleton中的框架类为父类,定义包括了具体实现的服务类,并创建服务对象的实例。
(2)、再向Servant端的ORB注册(发布)该对象,联系基本概念中对POA的描述-POA是Servant与ORB之间管理Object的媒介,向ORB注册、激活对象需要用到POA对象。则首先要创建并初始化ORB对象请求代理和POA(Portable Object Adaptor),使用POA Manager对象向ORB服务注册并激活SecretMessage对象。POA对服务程序而言非常重要,它是用于管理服务程序中所有可用对象的那个对象(在面向对象的程序设计中一切都是对象,除此之外没有别的),每个POA对象拥有自己的POA Manager,用于管理所有注册的对象。
(3)、创建了服务对象实例,启动ORB服务组件,获取了RootPOA Manager,接下来就要向ORB激活对象实例,激活的方法OurSecretMessage类已经从messenger__POA.SecretMessage类中继承获得,即_this()方法。本例中将服务对象的IOR字符串值写入message.ior文件中,我们可以通过Email的方式将IDL文件和message.ior文件发布给客户程序开发者。

---bof:messenger_server.py---
#!C:\Python24\python.exe
#以Skeleton类为基类,定义服务类的实现
import messenger, messenger__POA
class OurSecretMessage(messenger__POA.SecretMessage):
    def __init__(self, secret_message):
        self.secret_message = secret_message

def get_message(self):
        return self.secret_message

#创建服务对象实例
ourMessage = ourSecretMessage(“Hello, omniORBpy!”)

#初始化ORB、POA、POA_MANAGER对象
import sys
from omniORB import CORBA

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)
poa = orb.resolve_initial_references(“RootPOA”)
poa_manager = poa._get_the_POAManager()
poa_manager.activate()

#激活对象,对象的类从messenger_POA中继承了激活的方法_this()
message_obj = ourMessage._this()

#将对象引用字符串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()

#启动ORB
orb.run()
---eof---

Step4.编写客户脚本
从message.ior文件读取服务对象的IOR,将IOR对象化,调用服务对象的方法get_message(),将得到”Hello, omniORBpy!”字符串;

---bof:messenger_client.py---
#!C:\Python24\python.exe
import sys
from omniORB import CORBA
import messenger

#从message.ior文件读取服务对象的IOR
input_handle = open(“message.ior”, “r”)
ior = input_handle.read()
input_handle.close()

orb = CORBA.ORB_init(sys.argv, CORBA.ORB_ID)

#从IOR获取对象,导入到自己地址空间中
obj = orb.string_to_object(ior)
mo = obj._narrow(messenger.SecretMessage)

result = mo.get_message()
print result
---eof---

Step4.运行情况

(1)、启动服务程序
%WORKDIR%>messenger_server.py
(2)、启动客户程序
%WORKDIR%>messenger_client.py
Hello, omniORBpy!
(3)、在message.ior文件中存储者Servant激活对象的IOR
---bof:message.ior---
IOR:010000002000000049444c3a6d657373656e6765722f5365637265744d6573736167653a312e3000010000000000000064000000010102000c00000031302e33312e3230302e38005b0d00000e000000fe8db26a4300000d20000000000000000200000000000000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100
---eof---

现在只要把messenger.idl和meeage.ior文件发布给客户程序的开发者,客户程序可以从网络中任何位置获取这条消息了。

>>Example two:使用命名服务定位分布的对象

Example one中将对象的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
import CORBA
import messenger, messenger__POA

class OurSecretMessage(messenger__POA.SecretMessage):
    def __init__(self, secret_message):
        """Intialize with the secret message we're going to use.
        """
        self.secret_message = secret_message

    def get_message(self):
        return self.secret_message

our_message = OurSecretMessage("I don't want any spam!")

#初始化ORB、POA、POA_Manager对象
import sys
from omniORB import CORBA

#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_manager = poa._get_the_POAManager()
poa_manager.activate()

#初始化命名服务对象
import CosNaming

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_obj = our_message._this()

#将对象绑定到逻辑名"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.get_message()

print result
---eof---

(3)、运行情况

(a)、首先启动命名服务
C:\>omninames
omniORB: Warning: the local loop back interface (127.0.0.1) is used as this 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 is IOR:010000002b00000049444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f6e746578744578743a312e30000001000000000000005c000000010102000a0000003132372e302e302e3100f90a0b0000004e616d6553657276696365000200000000000000080000000100000000545441010000001c00000001000000010001000100000001000105090101000100000009010100
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 as this 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, omniORBpy!