Python Twisted系列教程12:改进诗歌下载服务器
作者:dave@http://krondo.com/a-poetry-transformation-server/ 译者:杨晓伟(采用意译)
你可以从这里从头阅读这个系列。
新的服务器实现
这里我们要新写一个Twisted版的服务器。然后,再来讨论一些Deferred的新功能。
在第九、十部分,我们提出了诗歌转换引擎这个概念。由于其实现太过简单,因此我们用随机选择来模拟了可能会出现转换失败的情景。但如果转换引擎位于服务器端,那么当服务器宕机就会出现真实的转换失败的情景了。
因此,在这部分我们要实现一个诗歌样式转换服务器,然后在一个部分,我们会重写我们的诗歌下载客户端来使用这一服务并且学习Deferred的新功能。
设计协议
到目前为止,服务器端与客户端之间的交互都是单向的。但样式转换服务需要两者进行双向交互-客户端将原始式样的诗歌发送给乳服务器,然后服务器将转换格式并将其发送给对应的客户端。因此,我们需要使用、或自己实现一个协议来实现这种交互。
我们设计服务器端可以提供若干种转换服务,而让客户端来进行选择。因此客户端需要向服务器端发送两部分信息:转换方式名与诗歌原始内容。服务器只是将转换格式之后的诗歌发送给客户端。这里使用到了简单的运程调用。
Twisted支持需要种协议来解决这个问题:XML-RPC,Perspective Broker,AMP。
但介绍使用其中任何一种都需要大量的时间,因此我们使用自己实现的协议。我们约定客户端发送内容格式如下:
转换名称.诗歌内容
我们将其以netstring格式编码,当然服务器回发的信息也是以netstring格式编码。由于netstring使用了length-encoding,因此客户端能够识别出服务器没有将完整诗歌回发的情况。如果你尝试一下前面的协议,其无法检测到中途中断传输的情况。
代码
新的服务器实现代码在twisted-server-1/transformedpoetry.py中。首先,我们定义了一个TransformService类:
class TransformService(object):
def cummingsify(self, poem):
return poem.lower()
这里我们仅仅实现了一种转换方法,我们可以不回新格式转换方法。有一个重要的地方需要注意:格式转换服务与具体协议的实现是完全分分离的。将协议逻辑与服务逻辑分开是Twisted编程中常见的模式。这样做可以通过多种协议实现同一种服务,以增加了代码的重用性。
下面看看factory的实现代码:
class TransformFactory(ServerFactory):
protocol = TransformProtocol
def __init__(self, service):
self.service = service
def transform(self, xform_name, poem):
thunk = getattr(self, 'xform_%s' % (xform_name,), None)
if thunk is None: # no such transform
return None
try:
return thunk(poem)
except:
return None # transform failed
def xform_cummingsify(self, poem):
return self.service.cummingsify(poem)
factory提供了一个transform的函数,protocol就是用它来代表客户端连接请求进行诗歌格式转换。
如果发现没有客户端请求的转换方法或转换失败,那么返回None。和TransformService一样,factory与具体的协议逻辑实现也是相互独立的。
有一个地方需要引起注意:我们通过xfomr_前缀式方法来获取服务方法。这种方法在Twisted中很常见,尽管前缀经常发生变化,并且他们经常是依赖于独立于factory的一个对象(如此处的 TransformService)这是一种防止客户端使用蓄意恶性代码来让服务器端执行的方法。这种方法也提供了实现由服务提供具体协议代理的机制。
下面是协议实现代码:
class TransformProtocol(NetstringReceiver):
def stringReceived(self, request):
if '.' not in request: # bad request
self.transport.loseConnection()
return
xform_name, poem = request.split('.', 1)
self.xformRequestReceived(xform_name, poem) def xformRequestReceived(self, xform_name, poem):
new_poem = self.factory.transform(xform_name, poem)
if new_poem is not None:
self.sendString(new_poem)
self.transport.loseConnection()
在这个协议的实现中,我们通过继承NetstringReceiver来利用了Twisted对netstrings的实现。基类很好的处理了编码与解码功能,我们需要做的就是实现stringReceived方法。换句话说,stringReceived接收的参数是客户端编码之后的诗歌,而无需我们再去添加额外的编码信息。而且基类同样管理着缓冲区,即当一首诗歌完整接收完再进行解码。
如果一切进展正常的话,我们会使用NetstringReceiver的 sendString方法来将格式转换成功后的诗歌发送给客户端。
注意我们是如何通过定义xformRequestReceived方法将收到的信息一步步推向更高的抽象层而实现了Twisted的模式。
一个简单的客户端
我们会在下一个部分来实现相应的客户端,这里使用一个简单的脚本来实现客户端,代码位于twisted-server-1/transform-test中。如果你运行服务器端于11000端口:
python twisted-server-1/transformedpoetry.py --port 11000
相应的运行脚本为:
./twisted-server-1/transform-test 11000
那么你会看到如下输出(经过netstring编码):
15:here is my poem,
讨论
在这个部分介绍了如下几个方面内容:
1.双向通信
2.基于Twisted已有的协议实现新协议
3.将协议实现与服务功能实现独立分开
双向通信的基本机制是很简单的。我们使用前面服务器端与客户端使用的相同的技术来写与读数据,唯一不同的是我们这次两者都使用了(读与写)。当然,一个复杂的协议需要复杂的代码来处理接收到的数据流与格式化输出的信息。这也是为什么使用已经存在的协议的原因。
如果你开始觉得写简单的协议已经很上手了,那么最好就开始看看Twisted对不同协议的实现。尽管写一些简单的协议有助理解Twisted的编程风格,但在一个真实的程序中,最好是复用那些已经实现并证明性能良好的协议。
最后一点是将协议解析逻辑与服务实现逻辑分开,这是Twisted编程中非常重要的一个模式。我们这个服务器程序只是一个演示,你可以想象一下真实的网络服务是相当复杂的。通过将服务与协议逻辑分开,你可以通过复用已有的服务代码来运行于其它的协议实现上。
图27展示了一个格式转换服务器通过两种协议提供格式转换服务(当然,我们的服务器只提供了一种协议):

图27 提供两种协议支持的格式转换服务器
虽然在图27中使用了两种协议,但他们也许是只有几个协议属性不同。factory共享相同的服务。这样实现了代码的复用。
Python Twisted系列教程12:改进诗歌下载服务器的更多相关文章
- Python Twisted系列教程11:改进诗歌下载服务器
作者:dave@http://krondo.com/your-poetry-is-served/ 译者:杨晓伟(采用意译) 你可以从这里从头阅读这个系列. 诗歌下载服务器 到目前为止,我们已经学习了大 ...
- Python Twisted系列教程8:使用Deferred的诗歌下载客户端
作者:dave@http://krondo.com/deferred-poetry/ 译者:杨晓伟(采用意译) 可以从这里从头开始阅读这个系列. 客户端4.0 我们已经对deferreds有些理解了 ...
- Python Twisted系列教程6:抽象地利用Twisted
作者:dave@http://krondo.com/and-then-we-took-it-higher/ 译者:杨晓伟(采用意译) 你可以从这里从头开始阅读这个系列. 打造可以复用的诗歌下载客户端 ...
- Python Twisted系列教程14:Deferred用于同步环境
作者:dave@http://krondo.com/when-a-deferred-isnt/ 译者:杨晓伟(采用意译) 你可以从这里从头开始阅读这个系列. 介绍 这部分我们要介绍Deferred的 ...
- Python Twisted系列教程10:增强defer功能的客户端
作者:dave@http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/ 译者:杨晓伟(采用意译) 可以从这 ...
- Python Twisted系列教程5:由Twisted支持的诗歌客户端
作者:dave@http://krondo.com/twistier-poetry/ 译者:杨晓伟(采用意译) 你可以从这里从头开始阅读这个系列 抽象地构建客户端 在第四部分中,我们构建了第一个使用 ...
- Python Twisted系列教程4:由Twisted支持的诗歌客户端
作者:dave@http://krondo.com/twisted-poetry/ 译者:杨晓伟(采用意译) 你可以在这里从头开始阅读这个系列. 第一个twisted支持的诗歌服务器 尽管Twist ...
- Python Twisted系列教程9:第二个小插曲,Deferred
作者:dave@http://krondo.com/a-second-interlude-deferred/ 译者:杨晓伟(采用意译) 可以从这里从头来阅读这个系列 更多关于回调的知识 稍微停下来再思 ...
- Python Twisted系列教程7:小插曲,Deferred
作者:dave@http://krondo.com/an-interlude-deferred/ 译者:杨晓伟(采用意译) 你可以从这里从头开始阅读这个系列 回调函数的后序发展 在第六部分我们认识这 ...
随机推荐
- idea常用插件
1. 装逼插件 1.1 activate-power-mode 其设置在菜单栏window——active-power-mode下设置颜色是否显示,窗口是否晃动等等 1.2 Backgrou ...
- Android 中Activity,Window和View之间的关系
转自:http://hi.baidu.com/xiaofanqing/blog/item/8261ac114ab14f64cb80c435.html 我这里根据我个人的理解来讲讲我个人对这3个概念的理 ...
- Java IO流读写文件的几个注意点
平时写IO相关代码机会挺少的,但却都知道使用BufferedXXXX来读写效率高,没想到里面还有这么多陷阱,这两天突然被其中一个陷阱折腾一下:读一个文件,然后写到另外一个文件,前后两个文件居然不 ...
- dojo chart详解
Dojo提供了一套很完善的统计图(Chart)接口,在dojox/charting下面,可以支持很多种类型的. .简介 Dojo统计图提供快速的.简单的接口实现美观的.交互性强的web统计图表的实现. ...
- 如何突破JAVA程序员三年的门槛
第一阶段:三年 我认为三年对于程序员来说是第一个门槛,这个阶段将会淘汰掉一批不适合写代码的人.这一阶段,我们走出校园,迈入社会,成为一名程序员,正式从书本 上的内容迈向真正的企业级开发.我们知道如何团 ...
- 查看 nginx 的并发连接数
通过查看Nginx的并发连接,我们可以更清除的知道网站的负载情况.Nginx并发查看有两种方法(之所以这么说,是因为笔者只知道两种),一种是通过web界面,一种是通过命令,web查看要比命令查看显示的 ...
- 浅析Python中bytes和str区别
本博转载自:Chown-Jane-Y的浅析Python3中的bytes和str类型 Python 3最重要的新特性之一是对字符串和二进制数据流做了明确的区分.文本总是Unicode,由str类型表示, ...
- Android中Activity的LauchMode(加载模式)
1.standard模式:一个task有多个Activity,一个Activity可以被实例化多次,可以放在不同的task中. 2.singleTop模式:该Activity在栈顶,同时收到启动该Ac ...
- LinuxCentos6安装中文输入法
第一步.先安装中文语言包: 执行以下命令 [root@bogon 桌面]# yum install fonts-chinese.noarch [root@bogon 桌面]# yum install ...
- tornado日志管理
默认数据格式 默认情况下,采用tornado的web框架运行起来之后,任何访问都会直接在控制台输出日志信息,格式如下: [I 160807 09:27:17 web:1971] 200 GET / ( ...