对象引用

对象引用
CORBA作为传统中间件的典型代表,强调屏蔽底层网络对上层应用的差异性来建立一个统一的位置视图,使得程序员可以使用经典的面向对象思想开发客户程序和服务程序,而不受底层网络具体通信协议的困扰。举例而说,假如程序员开发了两个对象A和B,A位于机器Host1上,而B位于机器Host2上,业务逻辑要求A调用B的方法method()。在传统的TCP/IP Socket编程中,程序员不得不自己设计通讯协议,编码格式,参数解析等模块。这些工作即烦琐又容易出错。而CORBA基本上将程序员从与底层网络相关的协议设计中解放出来。程序员只用在A的模块稍微增加几行代码就可以实现远程对象的访问。对象引用就是CORBA为解决分布式系统设计中对象位置的透明性而设计的。
让我们从问题出发讨论分析对象引用的基本概念。
在单一进程空间中,A对象要调用B对象的方法,A对象必须要获得B对象的指针(或引用)。然而在分布式系统中,将B的地址传递给A是没有意义的。因为两者不在同一个进程空间。如果假设B的地址存在于A的进程空间中,然后调用B的方法,将带来内存非法访问等异常。那么CORBA是怎么解决这个问题的?实际上,为了定位B对象,我们需要的是一个超级指针的概念。因为原始的指针只包含地址信息,我们就在超级指针中新增主机地址信息、进程信息和对象的标识这三项信息。这实际上就是CORBA规范中定义的IOR(互操作对象引用)的格式。IOR格式定义如下:接口ID:主机地址:对象关键字。其中接口ID是用来唯一标识对象接口信息的,使用于CORBA高级服务接口池。格式为"IDL:对象名字:版本号"。主机地址包含协议类型和具体的地址,对于TCP/IP,就是IP地址和端口号。前两项信息是标准定义,不同CORBA产品实现厂商必须遵循。对象关键字包含POA标识和对象ID两项信息。对象关键字的语义在规范中没有指出,依赖于厂商的实现。
IOR只是定义了分布式对象的位置格式。依然不是我们所要的编程级别的超级指针。我们需要的是一个能够隐藏底层网络信息和对象位置信息的指针。我们使用这个指针就可以如同单机环境编程一样,非常舒服的调用B对象的方法。CORBA是怎么做到的呢?CORBA在客户端提出了一个代理对象的概念,我们的超级指针指向的并不是远程对象,而是这个代理对象。代理对象的外部接口和B对象一样,但是其内部的实现负责了参数编码,建立连接,发送数据包,接受数据包,解码获得返回值等等繁琐的网络协议设计。当然,这些工作我们程序员并不用做,还记得上一节提到的IDL编译器吗,编译器会帮我们生成这样一个代理类。
有了这个代理对象,我们还必须想办法构造它。构造它时,必须指出远程对象的位置信息。怎么构造?有两种方法,一种是获得IOR信息,直接构造。由服务器端公布这个IOR字符串,我们想办法拿到IOR串,然后调用ORB的string_to_object方法创建代理对象。string_to_object是CORBA规范中定义的标准ORB方法,其声明如下:Object string_to_object(in string or)。返回值是Object类型。实际上Object类型是所有代理对象的基类,获得这个Object对象后,还要使用代理类的_narrow(Object obj)方法才能获得实际需要的代理对象。在CORBA规范中对输入参数定义了三种方法,一种是直接表达IOR本身,另一种是内容为IOR的文件的地址,还有一种是使用corbaloc地址。
1)IOR形式,则输入参数形式为"IOR:12412abc333000"的字符串,IOR是必须的,后面跟200到800个16进制形式的数字。这些数字就是IOR所带的信息。
2)文件形式:输入参数形式为"file:/IOR文件绝对地址"或者"relfile:/相对路径"
3)corbaloc形式:输入参数格式为"corbaloc:iiop:ip:port/对象名字"。其中corbaloc:iiop是格式必须要的,其后是IP地址,/后是对象名字。另外还有一种rir格式,详细见CORBA规范。

下面给出第2个方法的代码片段:

int commonproc(CORBA::ORB_ptr orb, int argc, char* argv[])
...{
//
// 从文件helloobj.ref中获取服务对象hello的引用
//

CORBA::Object_var obj = orb -> string_to_object("relfile:/helloobj.ref");
if(CORBA::is_nil(obj))//判断对象引用是否为空,不能与NULL判断,不是传统的指针概念
...{
cerr return -1;
}

Hello_var hello = Hello::_narrow(obj);
assert(!CORBA::is_nil(hello));

//
// 调用服务对象hello中的服务方法hello_world()
//
cout hello_world()'"
hello -> hello_world();

cout
return 0;
}

从代码可以发现,对于客户程序员,没有socket、没有阐述编解码、没有发包收包,一切都是那么自然

前两种方法比较简单,但客户端和服务器端依然存在耦合关系,因为我们必须要拿到这个IOR,而怎么拿到?又成了问题。当然如果你是在自己的机器上学习CORBA,服务器生成了一个IOR文件后,你把它拷贝到客户端的目录下也可以。第三种方法耦合度比较高,虽然没有IOR,但我们必须显示知道服务器对象的地址信息。
另一个方法是借助第三方,假设服务器和客户端有一个众说周知的名字服务,服务端new出B对象后,获得其对象引用,然后在名字服务上发布对象引用,建立一个逻辑名字到对象引用的映射。客户端只用在名字服务查询逻辑名即可获得对象引用。这种方法可以很好的实现服务程序的位置透明,服务程序可以随意改变位置信息,而客户程序对此并不感知。当然,名字服务也是对象,客户要使用它也必须获得其对象引用。ORB提供resolve_initial_interface方法获得名字服务,输入参数是"NameService",返回值是名字服务的对象引用。其方法定义为Object resolve_initial_interface(in string or)。

下面给出服务方通过名字服务发布对象引用的代码,java语言实现

// create and initialize the ORB
ORB orb = ORB.init(args, null);

// get reference to rootpoa & activate the POAManager
POA rootpoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));
rootpoa.the_POAManager().activate();

// create servant and register it with the ORB
HelloImpl helloImpl = new HelloImpl();
helloImpl.setORB(orb);

// get object reference from the servant
org.omg.CORBA.Object ref = rootpoa.servant_to_reference(helloImpl);
Hello href = HelloHelper.narrow(ref);

// get the root naming context
org.omg.CORBA.Object objRef =
orb.resolve_initial_references("NameService");
// Use NamingContextExt which is part of the Interoperable
// Naming Service (INS) specification.
NamingContextExt ncRef = NamingContextExtHelper.narrow(objRef);

// bind the Object Reference in Naming
String name = "Hello";
NameComponent path[] = ncRef.to_name( name );
ncRef.rebind(path, href);

System.out.println("HelloServer ready and waiting ...");

// wait for invocations from clients
orb.run();

通过这两种方法获得的指向代理对象的指针,在CORBA世界中称之为对象引用。对象引用只是一个指向代理对象的指针。实际的远程对象是否存在,客户是不知道的。如果远程对象并不存在,而调用其方法会产生Object_not_exist异常。另外,对象引用只能由服务程序发布,客户不能创建对象引用,客户只有获取对象引用并使用的权力。
总结,我们通过分析分布式系统设计的一些问题,讨论CORBA核心概念对象引用。了解了IOR和对象引用的获取方法。

你可能感兴趣的:(编程,应用服务器,网络协议,网络应用,IT厂商)