ice入门

来源:互联网 发布:xp怎么禁止安装软件 编辑:程序博客网 时间:2024/06/05 09:38
先从ice网站上下载ice 2.0 for windows,这个版本要求安装dotnet,安装完ice后,要设置一下系统变量
set ICE_HOME=d:\ice-2.0.0
set PATH=%ICE_HOME%\bin;%PATH%
set PYTHONPATH=%ICE_HOME%\bin;%ICE_HOME%\python
ice的文档里有一个入门的例子,从最简单的hello world程序开始来熟悉ice。


1.编写Slice定义---Printer.ice
module Demo {
       interface Printer {
           void printString(string s);
       };
};

2.编译Slice定义
创建python程序第一步是要编译我们的Slice定义,生成python代理和骨架。

e:\myex\>slice2py Printer.ice

生成了Printer_ice.py和Demo的子目录,现在不用关心生成的在Printer.ice里定义的Printer接口对应的Printer_ice.py的代码。

3.编写服务器
为了实现我们定义的Printer接口,我们必须创建一个子类。根据代码约定,子类必须以大写的 I 字母为后缀,所以我们定义为PrinterI:

class PrinterI(Demo.Printer):
   def printString(self, s, current=None):
       print s

PrintI继承一个基类Demo.Printer,它是由slice2py生成的。这个基类是抽象的,并包含了一个方法printString,printString的参数有两个,一个是s,还有一个参数是current,current的类型是Ice.Current。
Server.py的其他代码和PrintI一起列出来:

import sys, traceback, Ice
import Demo
class PrinterI(Demo.Printer):
   def printString(self, s, current=None):
       print s

status = 0
ic = None
try:
   ic = Ice.initialize(sys.argv)
   adapter = ic.createObjectAdapterWithEndpoints(
                     "SimplePrinterAdapter", "default -p 10000")
   object = PrinterI()
   adapter.add(object, Ice.stringToIdentity("SimplePrinter"))
   adapter.activate()
   ic.waitForShutdown()
except:
   traceback.print_exc()
   status = 1

if ic:
   # Clean up
   try:
       ic.destroy()
   except:
       traceback.print_exc()
       status = 1

sys.exit(status)


注意其中的一段代码结构

status = 0
ic = None
try:
   # Server implementation here...
except:
   traceback.print_exc()
   status = 1
if ic:
   # Clean up
   try:
       ic.destroy()
   except:
       traceback.print_exc()
       status = 1
sys.exit(status)  

主程序的主体包含了try块,这里是服务器的代码所在,except块则是捕获运行的异常。
代码退出之前,它要销毁communicator,这可是要点,是为了正常退出Ice run time状态
程序必须调用已经创建成功的communicator的destroy方法,否则就会造成不确定的行为。

try块的主体含有实际的服务器代码:
ic = Ice.initialize(sys.argv)
adapter = ic.createObjectAdapterWithEndpoints(
                "SimplePrinterAdapter", "default -p 10000")
object = PrinterI()
adapter.add(object, Ice.stringToIdentity("SimplePrinter"))
adapter.activate()
ic.waitForShutdown()

代码执行的步骤:
1)通过调用Ice.initialize()初始化Ice run time状态,传递sys.argv参数是因为服务器要接受一些命令行参数,调用initialize返回的结果是一个Ice::Communicator的引用。这是Ice run time 的主句柄。

2)我们调用Communicator实例上的createObjectAdapterWithEndpoints,创建一个对象适配器,传入的参数是“SimplePrinterAdapter"(适配器的名字)和“default -p 10000",后者是要适配器用缺省协议(Tcp/ip)在端口10000处侦听进来的请求。

3)第三步,服务器端的run time已经初始化了,我们实例化一个PrinterI对象,为我们的Printer接口创建一个子类

4)通过调用适配器的add方法,通知适配器有了一个新的子类(servant)存在,传入add的参数是我们刚刚实例化的子类(servant),再加上个标识符。在这里,“SimplePrinter"是servant的名字(如果我们有多个打印机,每个打印机都可以有不同的名字,更正确的说法是,都有不同的对象标识)。

5)接下来,我们调用适配器的activate方法来激活适配器(适配器最初是在holding 状态下创建的,如果我们有多个子类(servant),它们共享一个适配器,而在所有servant实例化之前我们又不想处理请求的话,这是很有用的)。

6)最后,我们调用waitForShutdown。这个方法挂起发出调用请求的线程,直到服务器实现终止。或者通过发出一个调用关闭run time,或者是对某个信号作出响应。(现在,当我们不再需要服务器是,我们会简单地在命令行上中断它)

注意:这里尽管有一些代码,但它们对所有的服务器都是一样的。你可以把这些代码放在一个辅助类里,然后就不用再管它了。(Ice提供了这样的辅助类,叫Ice::Application)。就实际的应用代码而言,服务器只有几行代码:三行定义PrinterI,加上两行代码实例化PrinterI对象,然后向对象适配器注册它。

4.编写客户端
客户端代码Client.py,和Server.py非常相似。下面是完整的代码:

import sys, traceback, Ice
import Demo

status = 0
ic = None
try:  
   ic = Ice.initialize(sys.argv)
   base = ic.stringToProxy("SimplePrinter:default -p 10000")
   printer = Demo.PrinterPrx.checkedCast(base)
   if not printer:
       raise RuntimeError("Invalid proxy")
   printer.printString("Hello World!")
except:
   traceback.print_exc()
   status = 1

if ic:
   # Clean up
   try:
       ic.destroy()
   except:
       traceback.print_exc()
       status = 1
sys.exit(status)

注意这里的代码结构和服务器是一样的。我们使用同样的try 和except来处理错误。try 块的代码执行顺序如下:

1)和在服务器中一样,我们调用Ice::initialize初始化Ice run time。

2)下一步是取得远程打印机的代理。我们通过在communicator上调用stringToProxy创建一个代理,它带有一个字符串参数“SimplePrinter:default -p 10000”,这个字符串里包含了服务器中用到的对象标识符和端口号(当然,在程序代码里直接对对象标识符和端口号进行硬性编码确实是个不好的做法,但现在我们先这样做,以后在手册的33章节可以看到在代码结构更好的方法)

3)stringToProxy返回的代理类型时Ice::ObjectPrx,这种类型是接口和类的继承树上的根节点。但是说到我们实际用的printer,我们要的是Demo::Print,而不是一个Object接口的代理。为此,我们要调用Demo.PrinterPrx.checkedCast进行向下转换,这个checked方法会发送一条消息给服务器,并询问:“这是一个Demo::Printer接口的代理吗?”,如果是,这个调用会返回一个Demo.PrintPrx类型的代理;否则,如果代理表示是其他的类型,这个调用会返回None。

4)我们测试向下转型是否成功,如果不成功,就抛出错误消息,中止。

5)好了,现在我们在我们的地址空间里有个活动的代理(应该是有生命周期的意思),可以调用printString方法,把"Hello World!"字符串传递给它,服务器就会在终端上打印这个字符串。

5.运行客户端和服务器
运行客户端和服务器之前,我们先在一个单独的窗口启动服务器:
$python Server.py
这时,我们看不到任何东西,因为服务器只是简单地等待客户和它连接。

我们在另一个窗口运行客户端:
$python Client.py
客户端运行之后退出,并不产生任何输出结果,但在服务器窗口中,我们会看到"Hello World!" 。要终止服务器,我们目前的做法是直接在命令行上中断它。