新的服务器实现

这里我们要新写一个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共享相同的服务。这样实现了代码的复用。

转载于:https://blog.51cto.com/zhuxianzhong/1605194

Twisted入门教程(12)相关推荐

  1. Twisted 入门 教程

    GitHub 地址:https://github.com/likebeta/twisted-intro-cn/tree/master/zh             https://github.com ...

  2. Twisted入门教程(9)

    第九部分:第二个小插曲,Deferred 可以从这里从头来阅读这个系列. 更多关于回调的知识 稍微停下来再思考一下回调的机制.尽管对于以Twisted方式使用Deferred写一个简单的异步程序已经非 ...

  3. python twisted教程_Python Twisted 学习系列20(转载stulife最棒的Twisted入门教程)

    第二十部分 轮子中的轮子: Twisted和Erlang 简介 在这个系列中,有一个事实我们还没有介绍,即混合同步的"普通Python"代码与异步Twisted代码不是一个简单的任 ...

  4. Twisted入门教程(3)

    第三部分:开始认识Twisted 可以从这里从头开始阅读这个系列. 用twisted的方式实现前面的内容 最终我们将使用twisted的方式来重新实现我们前面的异步模式客户端.不过,首先我们先稍微写点 ...

  5. Twisted入门教程(5)

    2019独角兽企业重金招聘Python工程师标准>>> 第五部分:由Twited支持的诗歌下载服务客户端 你可以从这里从头开始阅读这个系列 抽象地构建客户端 在第四部分中,我们构建了 ...

  6. Twisted入门教程(10)

    2019独角兽企业重金招聘Python工程师标准>>> 第十部分:增强defer功能的客户端 可以从这里从头开始阅读这个系列. 版本5.0 现在我们将要向诗歌下载客户端添加一些新的处 ...

  7. twisted入门教程之五:由Twited支持的诗歌下载服务客户端

    第五部分:由Twited支持的诗歌下载服务客户端 抽象地构建客户端 在第四部分中,我们构建了第一个使用Twisted的客户端.它确实能很好地工作,但仍有提高的空间. 首先是,这个客户端竟然有创建网络端 ...

  8. mysql数据库入门教程(12):变量讲解大全

    变量的介绍 #变量 /* 系统变量: 全局变量 会话变量 自定义变量: 用户变量 局部变量 */ 一.系统变量 说明:变量由系统定义,不是用户定义,属于服务器层面 注意:全局变量需要添加global关 ...

  9. webpack 3 零基础入门教程 #12 - 如何使用模块热替换 HMR 来处理 CSS

    模块热替换 是什么意思? 以前我们使用的 webpack --watch 或 webpack-dev-server 的功能是监听文件改变,就自动刷新浏览器,而这个 模块热替换 不用刷新浏览器,它是只让 ...

最新文章

  1. 探索未知种族之osg类生物---器官初始化四
  2. 使用Bioconda管理生信软件(以bwa为例)
  3. 前方车辆检测的常用方法
  4. netty 之 telnet HelloWorld 详解
  5. MySQL中间件之ProxySQL(13):ProxySQL集群
  6. JAVA 边界布局管理器
  7. 禅道项目管理_禅道项目管理软件 v12.5.1 开源版
  8. 【Java】深入探讨Java数值舍入问题
  9. Python根据正则表达式找到相应的字符串然后进行替换
  10. .Net发布到服务器出现必须添加对程序集“System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=的问题
  11. 33-高级特性之generator(1)
  12. 关于 笔记本换掉光驱加装全新SSD以及win10系统无损迁移到SSD 详细教程
  13. 【设计配色宝典】设计师必备七色配色宝典,附AI源文件!
  14. 忘记卡巴斯基内置账户密码 / 取消卡巴斯基密码保护
  15. S7-1200PLC通过增量式编码器实现速度采集和模拟量采集
  16. 7.3.2 B+树的基本概念
  17. 【创新实训】BERT4EL,基于文本相似度的实体消歧实现
  18. 亚马逊EC2使用账号密码登录
  19. 银行卡收单____对账__单边账
  20. 数据结构当中的二元组详解

热门文章

  1. 凝思系统分辨率怎么看_机械液压系统的泄漏怎么办,液压系统基本知识,看完你就懂了...
  2. java多递归调用_java – 递归调用方法
  3. python 异常处理模块_我的python学习之路-异常处理和模块导入
  4. FPGA的设计艺术(12)使用parameter构建可重用的逻辑设计
  5. IC基础知识(1)集成电路(IC)简介
  6. FPGA设计心得(3)Aurora IP core 的理论学习记录
  7. 【 MATLAB 】数字信号处理中的几个常用序列产生的MATLAB代码
  8. 驰骋工作流引擎设计系列04 流程引擎表结构的设计
  9. 解决Android 7.0 App内切换语言不生效的问题
  10. 关于MATLAB处理大数据坐标文件2017529