迄今为止我们是用的string_to_object() 和object_to_string()
来引导客户端启动的。如果系统要用于真正的分布式环境,我们就不能依靠共享分件系统或让用户输入IOR来初始化客户端了。为了达到这个目的,CORBA提供了几种定位服务。其中最简单的服务是CORBA命名服务。有许多好的教程讲述了如何使用命名服务,另外在Henning 的Vinoski 的书中还详细讨论了命名服务的问题。
在本节中,我们只会涉及到命名服务的简单使用,会集中到如何配置和引导命名服务的引导启动上。包括了TAO支持的可交互式命名服务(Interoperable Naming Service)。
首先我们修改服务器以便于把股票工厂和命名服务注册。这需要包含正确的头文件:
#include "orbsvcs/CosNamingC.h"
我们使用下面的方法重新激活股票工厂:
// Activate it to obtain the object reference
Quoter::Stock_Factory_var stock_factory =
stock_factory_i._this ();
我们需要找回命名对象的引用,这步操作使用resolve_initial_references() 来完成。
CORBA::Object_var naming_context_object =
orb->resolve_initial_references ("NameService");
CosNaming::NamingContext_var naming_context =
CosNaming::NamingContext::_narrow (naming_context_object.in ());
接下来我们初始化要为对象赋值的名字。命名服务服为名字使用结构的序列——可以想像为把路径分解为目录名。在本例中我们使用简单的名字。在产品化的环境中使用有更好组织层次的命名服务可能是更需要的。第一步是创建和初始化序列:
CosNaming::Name name (1);
name.length (1);
接下来初始化名字:
name[0].id = CORBA::string_dup ("Stock_Factory");
现在我们准备把对象引用注册到命名服务中:
naming_context->bind (name, stock_factory.in ());
注意,如果在命名服务中已注册了这个名字,那么 bind()
会失败。这时,您可以使用 rebind()覆盖原来的值。
现在我们可以通过命名服务来定位对象。用于替代对命令行的依赖,我们必须执行相同的调用来定位命名服务和初始化我们要查找的对象的名名字:
CORBA::Object_var naming_context_object =
orb->resolve_initial_references ("NameService");
CosNaming::NamingContext_var naming_context =
CosNaming::NamingContext::_narrow (naming_context_object.in ());
CosNaming::Name name (1);
name.length (1);
name[0].id = CORBA::string_dup ("Stock_Factory");
接下来我们可以解析这个名字:
CORBA::Object_var factory_object =
naming_context->resolve (name);
Quoter::Stock_Factory_var factory =
Quoter::Stock_Factory::_narrow (factory_object.in ());
到这一步我们就可以像以前那样使用它了。
完成对文件 server.cpp
的变更。
为了完成和测试你的实现,您可以使用下面的文件: Quoter.idl, Makefile, Stock_i.h, Stock_i.cpp, Stock_Factory_i.h Stock_Factory_i.cpp。为了更有趣,您也可以修改原始的 client.cpp 文件。第一个参数怎么样?现在我们还需要IOR么?
把您的解决方案与文件 client.cpp 和server.cpp作比较。它们应该很相似。
为了测试您的变更需要运行四个程序。第一个在您的局域网中配置TAO的命名服务查寻协议以便使用唯一的端口。这个端口基于您的用户ID是一个好主意。例如:
$ setenv NameServicePort `expr 10000 + $uid`
现在我们可以启动TAO提供的命名服务了:
$ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service
以及您的服务端:
$ server
最后是您的客户端:
$ client MSFT RHAT RHAT MSFT
那么TAO怎么找寻命名服务的呢?直到近期也没有标准的方式来配置命名服务器如何启动。在TAO中我们决定使用多播来定位服务端。多播协议虽然简单,但在不是有许多命名服务运行的小的局域网中工作还是工作得非常好。为了避免当在同一个局域网中运行多个命名服务的问题时,像上面那样,您必须为每个服务指定不同的多播端口。
不幸的是,上面的协议并不能在跨多个局域网中工作,并且很难保证在多播端口的分配上不冲突。TAO支持交互多命名服务规范,该规范提供了许多机制用于控制resolve_initial_references() 调用的行为。例如:您可以让命名服务输出它的IOR到文件中,像下面这样。
$ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -o ns.ior
然后用-ORBInitRef 用那个IOR文件代替多播协议:
$ server -ORBInitRef NameService=`cat ns.ior`
或者更好的方法使用file:scheme的方式直接读取文件:
$ server -ORBInitRef NameService=file://ns.ior
但这依然假定在主机之间存在共享的文件系统,或者需要用户跨过网络复制文件。如果我们知道接受IIOP请求的命名服务使用的主机和端口,那么我们就可以使用corbaloc: scheme 方式:
$ server -ORBInitRef NameService=corbaloc:iiop:ace.cs.wustl.edu:12345/NameService
实际上,对任务TAO程序(包括了命名服务)的主机和端口的控制很简单。仅仅要求您使用 -ORBEndPoint
option选项就行了。
$TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -ORBEndPoint iiop://ace.cs.wustl.edu:12345
当然,它只能够当您在主机ace.cs.wustl.edu 上运行您的程序,并且端口12345可用的前提下或以工作。您可以使用神奇的端口号0让ORB为您寻找一个可用的端口,实际上这正好是TAO默认这样执行的。
最好,你可以使用多个-ORBEndPoint 选项在多个端点上侦听。在对一有多个地址的主机非常有用。
试着使用不同的方法查寻命名服务。再试着为命名服务指派一个无效的IOR运行服务器。如果服务器或客户端通过多播协议选取不同的命名服务会怎么样呢?如果他们的配置与期望的命名服务器不一致会怎么样呢?
如果命名服务在对象注册和查询之间关掉了会怎么样呢?默认情况下TAO的命名服务不是持久化的,但解决办法是使用标记把状态存放文件中:
$ $TAO_ROOT/orbsvcs/Naming_Service/Naming_Service -f name_service.dat
注意:除非您的服务使用了持久化,或者它可以自动重启,本节的示例就没有多大的用处。解决持久化是实现仓库的职责。