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/ 译者:杨晓伟(采用意译) 你可以从这里从头开始阅读这个系列 回调函数的后序发展 在第六部分我们认识这 ...
随机推荐
- C语言小知识点汇集
1. 三元表达式“?:”冒号两边的两个操作数类型必须一致. 2. 枚举变量的sizeof值同int型一样为4. 3. 为了消除不必要的计算 &&两侧的表达式,当左侧即第1个表达式不成立 ...
- win8里DNW的裸机程序下载
1. win8要装DNW驱动首先要禁止驱动数字签名(参考百度经验:http://jingyan.baidu.com/article/3f16e003d1f4612591c103ce.html) 2.然 ...
- OC-如何隐藏NSLog打印的自带信息
#ifdef DEBUG #define NSLog(FORMAT, ...) fprintf(stderr,"%s\n",[[NSString stringWithFormat: ...
- head插件对elasticsearch 索引文档的增删改查
1.RESTful接口使用方法 为了方便直观我们使用Head插件提供的接口进行演示,实际上内部调用的RESTful接口. RESTful接口URL的格式: http://localhost:9200 ...
- win+D可以最小化所有窗口,显示桌面 win+E可以快速打开我的电脑 这两个对我来说非常常用,要用熟练,节约时间
win+D可以最小化所有窗口,显示桌面 win+E可以快速打开我的电脑
- Leetcode 986. Interval List Intersections
暴搜.. class Solution(object): def intervalIntersection(self, A: List[Interval], B: List[Interval]) -& ...
- (一)Nginx正向代理与反向代理
引言:身为前端开发人员来说对于Nginx的作用或许很少听到,这个东西是后端使用的,Nginx对前端而言意味着什么,有什么用呢?大白会整理出几篇文章给大家细细道来. 1.正向代理的概念 正向代理,也就是 ...
- 【vs2013】如何在VS的MFC中配置使用GDI+?
摘自:http://www.cnblogs.com/CSGrandeur/p/3156843.html (已实验,可行) 1.配置GDI+ VS2010自带GDI+,直接使用. (1)首先要添加头文件 ...
- 深入理解vsto,开发word插件的利器
开发了vsto,客户那边也有一些反映插件安装失败或者加载不上的情况.于是我下定决定再理解下vsto的工作机制,如下图: 如上图所示,我把vsto的解决方案分为两部分,一部分是vsto Add-ins, ...
- 洛谷P2835 刻录光盘
传送门 题目大意:有光盘可以传着看,问最少从哪几个人分发,能全部传一遍. 题解:缩点后求入度为0的点的个数 代码: #include<iostream> #include<cstdi ...