Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5096535
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2012-04-06 23:57:06

I've been using Twisted's Perspective Broker to manage networking for my Python program. Perspective Broker allows me to run a Python program on a remote machine and perform remote method calls on an object in the Python program. It also allows me to serialize objects and transfer them over TCP.

Once I got a Perspective Broker server and client running, I wanted to create a "Twisted Application" and run it using twistd, the Twisted Daemon. Two major options are: creating a .tac file and creating a twistd plugin. Below, I show the steps I took to create a .tac application script and a twistd plugin using a simple Perspective Broker example.

Basic Perspective Broker server and client

Here is a simple Perspective Broker server and client example which I adapted from Twisted's examples page. The PB server code lives in pbsimpleserver.py:

  1. from twisted.spread import pb
  2. from twisted.internet import reactor

  3. class Echoer(pb.Root):
  4.     def remote_echo(self, st):
  5.         print 'echoing:', st
  6.         return st

  7. if __name__ == '__main__':
  8.     serverfactory = pb.PBServerFactory(Echoer())
  9.     reactor.listenTCP(8789, serverfactory)
  10.     reactor.run()

Here is a simple PB client, pbsimpleclient.py:


 

  1. from twisted.spread import pb
  2. from twisted.internet import reactor

  3. class EchoClient(object):
  4.     def connect(self):
  5.         clientfactory = pb.PBClientFactory()
  6.         reactor.connectTCP("localhost", 8789, clientfactory)
  7.         d = clientfactory.getRootObject()
  8.         d.addCallback(self.send_msg)
  9.         
  10.     def send_msg(self, result):
  11.         d = result.callRemote("echo", "hello network")
  12.         d.addCallback(self.get_msg)

  13.     def get_msg(self, result):
  14.         print "server echoed: ", result
  15.         
  16. if __name__ == '__main__':
  17.     EchoClient().connect()
  18.     reactor.run()

This code connects the client to the server using port 8789. It sends a message by calling the server's remote_echo method with an argument of "hello network". The server prints the message and returns the same message to the client. The client then prints the message.

To test the code, I ran both client and server on my local machine. I ran python pbsimpleserver.py in one terminal shell, then ran python pbsimpleclient.py in another shell. In the server shell, I got:


 

  1. echoing: hello network


 

and in the client shell I got:


  1. server echoed: hello network


 

To stop the client and server, I hit CTRL-C in both shells

Converting to a Twisted Application (.tac script)

To create a Twisted application, I used the twisted.application.service.Application object. When converting the example code above to an Application, I replaced twisted.internet.reactor.listenTCP with twisted.application.internet.TCPServer and twisted.internet.reactor.connectTCP with twisted.application.internet.TCPClient. Below is my server application, pbsimpleserver_app.py. (Note: the two files below are considered .tac files even though the filename doesn't end in .tac. From the documentation, .tac files are Python files which configure an Application object and assign this object to the top-level variable "application".)

from twisted.spread import pb from twisted.application.internet import TCPServer from twisted.application.service import Application class Echoer(pb.Root): def remote_echo(self, st): print 'echoing:', st return st serverfactory = pb.PBServerFactory(Echoer()) application = Application("echo") echoServerService = TCPServer(8789, serverfactory) echoServerService.setServiceParent(application)

Here is my client application, pbsimpleclient_app.py:

from twisted.spread import pb from twisted.application.internet import TCPClient from twisted.application.service import Application class EchoClient(object): def send_msg(self, result): d = result.callRemote("echo", "hello network") d.addCallback(self.get_msg) def get_msg(self, result): print "server echoed: ", result e = EchoClient() clientfactory = pb.PBClientFactory() d = clientfactory.getRootObject() d.addCallback(e.send_msg) application = Application("echo") echoClientService = TCPClient("localhost", 8789, clientfactory) echoClientService.setServiceParent(application)

To run these as daemons with twistd, I executed:

twistd -l server.log --pidfile server.pid -y pbsimpleserver_app.py

then:

twistd -l client.log --pidfile client.pid -y pbsimpleclient_app.py

This created the log file, server.log:

2008-10-27 00:08:35-0700 [-] Log opened. 2008-10-27 00:08:35-0700 [-] twistd 8.1.0 (/usr/bin/python 2.5.2) starting up 2008-10-27 00:08:35-0700 [-] reactor class: 2008-10-27 00:08:35-0700 [-] twisted.spread.pb.PBServerFactory starting on 8789 2008-10-27 00:08:35-0700 [-] Starting factory 2008-10-27 00:08:53-0700 [Broker,0,127.0.0.1] echoing: hello network

and client.log:

2008-10-27 00:08:53-0700 [-] Log opened. 2008-10-27 00:08:53-0700 [-] twistd 8.1.0 (/usr/bin/python 2.5.2) starting up 2008-10-27 00:08:53-0700 [-] reactor class: 2008-10-27 00:08:53-0700 [-] Starting factory 2008-10-27 00:08:53-0700 [Broker,client] server echoed: hello network


 

Creating a twistd plugin

In order to pass command line arguments to my Twisted application daemon, I need to create a twistd plugin. The following is how I implemented my plugin after reading the Writing a twistd plugin documentation. Here is my directory structure. EchoProj is located in ~/Projects.

EchoProj |-- echoproj | |-- __init__.py | |-- pbsimpleclient.py | `-- pbsimpleserver.py `-- twisted `-- plugins |-- echoclient_plugin.py `-- echoserver_plugin.py

pbsimpleserver.py:

from twisted.spread import pb class EchoServer(pb.Root): def remote_echo(self, st): print 'echoing:', st return st

pbsimpleclient.py:

class EchoClient(object): def send_msg(self, result): d = result.callRemote("echo", "hello network") d.addCallback(self.get_msg) def get_msg(self, result): print "server echoed: ", result

echoserver_plugin.py:

from zope.interface import implements from twisted.python import usage from twisted.plugin import IPlugin from twisted.application.service import IServiceMaker from twisted.application.internet import TCPServer from twisted.spread import pb from echoproj.pbsimpleserver import EchoServer class Options(usage.Options): optParameters = [["port", "p", 8789, "The port number to listen on."]] class MyServiceMaker(object): implements(IServiceMaker, IPlugin) tapname = "echoserver" description = "Echo Server" options = Options def makeService(self, options): serverfactory = pb.PBServerFactory(EchoServer()) return TCPServer(int(options["port"]), serverfactory) serviceMaker = MyServiceMaker()

echoclient_plugin.py:

from zope.interface import implements from twisted.python import usage from twisted.plugin import IPlugin from twisted.application.service import IServiceMaker from twisted.application.internet import TCPClient from twisted.spread import pb from echoproj.pbsimpleclient import EchoClient class Options(usage.Options): optParameters = [["port", "p", 8789, "The port number to connect to."], ["host", "h", "localhost", "The host machine to connect to."] ] class MyServiceMaker(object): implements(IServiceMaker, IPlugin) tapname = "echoclient" description = "Echo Client" options = Options def makeService(self, options): e = EchoClient() clientfactory = pb.PBClientFactory() d = clientfactory.getRootObject() d.addCallback(e.send_msg) return TCPClient(options["host"], int(options["port"]), clientfactory) serviceMaker = MyServiceMaker()

I set the PYTHONPATH to include the top-level project directory:

export PYTHONPATH="$HOME/Projects/EchoProj:$PYTHONPATH"

Running twistd --help now showed "echoserver" and "echoclient" in the list of commands. To run my server and client as daemons using port 8790 on my local machine, I executed:

twistd -l server.log --pidfile server.pid echoserver -p 8790

and

twistd -l client.log --pidfile client.pid echoclient -p 8790

This produced the logfiles, server.log:

2008-10-27 11:49:12-0700 [-] Log opened. 2008-10-27 11:49:12-0700 [-] twistd 8.1.0 (/usr/bin/python 2.5.2) starting up 2008-10-27 11:49:12-0700 [-] reactor class: 2008-10-27 11:49:12-0700 [-] twisted.spread.pb.PBServerFactory starting on 8790 2008-10-27 11:49:12-0700 [-] Starting factory 2008-10-27 11:49:17-0700 [Broker,0,127.0.0.1] echoing: hello network

and client.log:

2008-10-27 11:49:17-0700 [-] Log opened. 2008-10-27 11:49:17-0700 [-] twistd 8.1.0 (/usr/bin/python 2.5.2) starting up 2008-10-27 11:49:17-0700 [-] reactor class: 2008-10-27 11:49:17-0700 [-] Starting factory 2008-10-27 11:49:17-0700 [Broker,client] server echoed: hello network

from:
http://www.saltycrane.com/blog/2008/10/running-twisted-perspective-broker-example-twistd/

阅读(1152) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~