URN Logo
UNIX Resources » Linux » China Linux Forum » Python 编 程 » 4 » [精华] 啃嚼Twisted的初感
announcement 声明: 本页内容为中国Linux论坛的内容镜像,文章的版权以及其他所有的相关权利属于中国Linux论坛和相应文章的作者,如果转载,请注明文章来源及相关版权信息。
Resources
China Linux Forum(finished)
Linux Forum(finished)
FreeBSD China(finished)
linuxforum.net
  业界新闻与评论
  自由软件杂谈
  IT 人生
  Linux软件快递
  翻译作坊
  Linux图书与评论
  GNU Emacs/XEmacs
  Linux 中文环境和中文化
  Linux桌面与办公软件
  Linux 多媒体与娱乐版
  自由之窗Mozilla
  笔记本电脑上的Linux
  Gentoo
  Debian 一族
  网络管理技术
  Linux 安装与入门
  WEB服务器和FTP服务器
  域名服务器和邮件服务器
  Linux防火墙和代理服务器应用
  文件及打印服务器
  技术培训与认证
  Linux内核技术
  Linux 嵌入技术
  Linux设备驱动程序
  Linux 集群技术
  LINUX平台数据库
  系统和网络安全
  CPU 与 编译器
  系统计算研究所专栏
  Linux下的GUI软件开发
  C/C++编程版
  PHP 技 术
  Java&jsp技术
  Shell编程技术
  Perl 编 程
  Python 编 程
  XML/Web Service 技术
  永远的Unix
  FreeBSD世界
   
[精华] 啃嚼Twisted的初感
[精华] 啃嚼Twisted的初感 - lawme [2005-11-27 23:02 | 422 byte(s)]
 
[精华] Re: 啃嚼Twisted的初感 - lawme [2005-11-28 06:42 | 298 byte(s)]
 
[精华] Re: 啃嚼Twisted的初感 - limodou [2005-11-28 08:49 | 104 byte(s)]
 
[精华] Re: 啃嚼Twisted的初感 - lawme [2005-11-28 19:10 | 656 byte(s)]
 
[精华] Re: 啃嚼Twisted的初感 - lawme [2005-11-30 07:36 | 2,729 byte(s)]
 
[精华] Re: 啃嚼Twisted的初感 - limodou [2005-11-30 10:04 | 86 byte(s)]
 
Re: 啃嚼Twisted的初感 - lawme [2005-12-01 07:23 | 3,949 byte(s)]
 
Re: 啃嚼Twisted的初感 - passworld [2005-12-02 19:22 | 980 byte(s)]
 
Re: 啃嚼Twisted的初感 - panhudie [2005-12-02 21:00 | 315 byte(s)]
 
Re: 啃嚼Twisted的初感 - lawme [2005-12-02 23:25 | 206 byte(s)]
 
Re: 啃嚼Twisted的初感 - lawme [2005-12-07 00:19 | 5,359 byte(s)]
 
请版主帮忙修正一个错误 - lawme [2005-12-01 08:37 | 536 byte(s)]
 
Re: 请版主帮忙修正一个错误 - limodou [2005-12-01 09:29 | 842 byte(s)]
 
三、创建 client 的套路 - lawme [2005-12-02 11:57 | 2,852 byte(s)]
 
Subject: [精华] 啃嚼Twisted的初感
Author: lawme    Posted: 2005-11-27 23:02    Length: 422 byte(s)
[Original] [Print] [Top]
生硬、苦涩,劳神费劲。

Twisted,恰如其名,不折不扣的“弯弯绕“。

啃嚼过程,多半是体力活,不停地点击mouse,从API文档到源代码,跳来跳去,四处寻觅。

真累。手酸、眼花、头晕、心烦,精神健康大致进入“亚”级状态了。呵呵。

最大的痛苦是不知所云。这个framework够诡异的。

但愿逐渐适应它的套路,尽早解开这个“弯弯绕“。

[Original] [Print] [Top]
Subject: [精华] Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-11-28 06:42    Length: 298 byte(s)
[Original] [Print] [Top]
Twisted应用的基本问题,可说是“一个中心,两个基本点”,即:

以“事件”event为中心,以"建立连接"connect和“定义反馈“callback为基本点。

在这些问题上,Twisted有一整套固定的路数,只能照章行事,没有自由发挥的余地。



[Original] [Print] [Top]
Subject: [精华] Re: 啃嚼Twisted的初感
Author: limodou    Posted: 2005-11-28 08:49    Length: 104 byte(s)
[Original] [Print] [Top]
好呀。我一直都没有看过,还是在啄木鸟上听过几次讲课,但平时不会这块东西一直没有感觉。有什么经验分享之哪。
----
[Original] [Print] [Top]
Subject: [精华] Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-11-28 19:10    Length: 656 byte(s)
[Original] [Print] [Top]
好吧。继续说说遇到的麻烦。

一、windows下的软件包里没有文档,还需下载unix下的软件包。两个包分别是:
Twisted_NoDocs-2.1.0.win32-py2.4.exe
Twisted-2.1.0.tar

二、文档没有API的,只能上网抓
我用teleport pro抓下它的API的全部在线文档,总共34MB,是软件包的17倍。

三、文档做得粗糙,比java的差远了,只能将就用吧。

四、它有个package叫internet,里面有个管理标准I/O的模块stdio.py,它import了fdesc.py,fdesc.py又import了fcnt1.py。缺了这个文件,无法使用stdio。
这个fcnt1.py是属于python的,但是,windows下的python却没有fcnt1.py,致使有的例程无法运行。
[Original] [Print] [Top]
Subject: [精华] Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-11-30 07:36    Length: 2,729 byte(s)
[Original] [Print] [Top]
  啃嚼快一星期了,不再痛苦难受,逐渐尝出twisted的香甜美味、柔顺可口,开始适应twisted的套路。

  twisted的套路,有哪些显著特点呢?接下去说说我品尝出的滋味。

  前面把twisted的套路概括成一句话,“一个中心,两个基本点”,现在就从这个“中心”聊起。

  Twisted 官方说,“ Twisted is an event-driven networking framework ”。事实的确如此。从其运行机制上看,event 是 Twisted 运转的引擎,是发生各种动作的启动器,是牵一发而动全身的核心部件。从其架构组成上看,它是紧密围绕event设计的;它的具体应用application,主要是定义、实现各式各样的event,由此完成不同网络协议的连接和输入输出任务,满足用户的实际需求;从其application的文本形式上,可以直接看到,它的应用程序,基本上由一系列event构成。

  由此可见,说它以event为中心,符合实际情况。

  Twisted 对event 的管理机制,可划分为后台和前台两种形式。

  后台的管理,是Twisted 框架的内在机制,自动运行,对程序员透明无须干预,在程序文本中不见其踪迹。

  前台的管理,是Twisted 授权程序员,在程序文本中显式写码来实现。程序员的工作,主要是按照既定的方式,实现 event。我们所关心、所用到的,是这部分东西(API)。

  Twisted 众多的 event,分门别类、层次有序。前台管理中,有两个特别的 object,一个叫 reactor ,另一个叫defered。特别之处,在于它俩起着“事件管理器”的作用。下面,说说它俩。

  一、统领全局的 reactor

  在 Twisted 应用中,reactor 的任务是为程序运行建立必须的全局循环(event loop),所起的作用,相当于 Python 应用中的 MainLoop()。

  reactor 的用法很简单,一般只用两个:reactor.run() 启动全局循环,reactor.stop() 停止全局循环(程序终止)。

  如果程序中没有调用reactor.stop() 的语句,程序将处于死循环,可以按键 Ctrl-C 强制退出。

  下面是一个例子:

from twisted.internet import reactor

import time

def printTime( ):

  print "Current time is", time.strftime("%H:%M:%S")


def stopReactor( ):

  print "Stopping reactor"

  reactor.stop( )


reactor.callLater(1, printTime)
  #定时器,1秒钟后调用printTime()

reactor.callLater(2, printTime)

reactor.callLater(3, printTime)

reactor.callLater(5, stopReactor)
  #定时器,5秒钟后调用stopReactor()

print "Running the reactor..."

reactor.run( )

print "Reactor stopped."



[Original] [Print] [Top]
Subject: [精华] Re: 啃嚼Twisted的初感
Author: limodou    Posted: 2005-11-30 10:04    Length: 86 byte(s)
[Original] [Print] [Top]
非常好。如果有个人的blog的话,同时放在上面会更好。如果不介意可以放在啄木鸟的wiki上去。
----
[Original] [Print] [Top]
Subject: Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-12-01 07:23    Length: 3,949 byte(s)
[Original] [Print] [Top]
  谢谢版主的鼓励。woodpecker wiki 我不会操作,请您适当处理。

  二、提升效率的 defferred

  Twisted 官方称,“Twisted is event-based, asynchronous framework ”。这个“异步”功能的代表就是 defferred。

  defferred 的作用类似于“多线程”,负责保障多头连接、多项任务的异步执行。

  当然,defferred “异步”功能的实现,与多线程完全不同,具有以下特点:

  1、defferred 产生的 event,是函数调用返回的对象;

  2、defferred 代表一个连接任务,负责报告任务执行的延迟情况和最终结果;

  3、对defferred 的操作,通过预定的“事件响应器”(event handler)进行。

  有了defferred,即可对任务的执行进行管理控制。防止程序的运行,由于等待某项任务的完成而陷入阻塞停滞,提高整体运行的效率。

  请看下面的例子:

  建议只关注黑体字的语句,它们反映了defferred的用法。涉及的两个class,是Twisted建立网络连接的固定套路,后面会专门说它。

# connectiontest.py
from twisted.internet import reactor, defer, protocol

class CallbackAndDisconnectProtocol(protocol.Protocol):
# Twisted建立网络连接的固定套路

  def connectionMade(self):

    self.factory.deferred.callback("Connected!")
    # “事件响应器”handleSuccess对此事件作出处理

    self.transport.loseConnection( )


class ConnectionTestFactory(protocol.ClientFactory):
# Twisted建立网络连接的固定套路

  protocol = CallbackAndDisconnectProtocol

  def __init__(self):

    self.deferred = defer.Deferred( )
    # 报告发生了延迟事件,防止程序阻塞在这个任务上

  def clientConnectionFailed(self, connector, reason):

    self.deferred.errback(reason)
    # “事件响应器”handleFailure对此事件作出处理

def testConnect(host, port):

  testFactory = ConnectionTestFactory( )

  reactor.connectTCP(host, port, testFactory)

  return testFactory.deferred
  # 返回连接任务的deferred


def handleSuccess(result, port):
# deferred“事件响应器”:连接任务完成的处理

  print "Connected to port %i" % port

  reactor.stop( )


def handleFailure(failure, port):
# deferred“事件响应器”:连接任务失败的处理

  print "Error connecting to port %i: %s" % (

  port, failure.getErrorMessage( ))

  reactor.stop( )


if __name__ == "__main__":

  import sys

  if not len(sys.argv) == 3:

  print "Usage: connectiontest.py host port"

  sys.exit(1)


  host = sys.argv[1]

  port = int(sys.argv[2])

  connecting = testConnect(host, port)
  # 调用函数,返回deferred

  connecting.addCallback(handleSuccess, port)
  # 建立deferred“事件响应器”

  connecting.addErrback(handleFailure, port)
  # 建立deferred“事件响应器”

  reactor.run( )

---------------------------------------------------------------------------------

程序的运行,在命令行:

python connectiontest.py linuxforum.net 80
[Original] [Print] [Top]
Subject: 请版主帮忙修正一个错误
Author: lawme    Posted: 2005-12-01 08:37    Length: 536 byte(s)
[Original] [Print] [Top]
错误出现在昨天的贴子里。

原文:
  ……

  Twisted 众多的 event,分门别类、层次有序。前台管理中,有两个特别的 event ,一个叫 reactor ,另一个叫defered。特别之处,在于它俩起着“事件管理器”的作用。下面,说说它俩。

  一、统领全局的 reactor

  ……

其中,“有两个特别的 event”,应当改为“有两个特别的 object”。

该贴我已无权修改,请版主代劳。
[Original] [Print] [Top]
Subject: Re: 请版主帮忙修正一个错误
Author: limodou    Posted: 2005-12-01 09:29    Length: 842 byte(s)
[Original] [Print] [Top]
已经改好了。并且我在wiki上为你建了一个页面,并且我文章上传。对于第二篇中提到的黑体字,不知道在处理代码行如何实现,我改为“特别注释”了。

你可以访问:

http://wiki.woodpecker.org.cn/moin/LawMe

进入你个人页面。如果要修改文单可以先点击右上角的UserPreferences进行注册。http://wiki.woodpecker.org.cn/moin/UserPreferences

同时在行者堂 http://wiki.woodpecker.org.cn/moin/WoodpeckerHackers注册你的用户。我给你起的名字是 LawMe 。建议学一学wiki,不是很困难,存放个人的东西的很方便。
----
[Original] [Print] [Top]
Subject: 三、创建 client 的套路
Author: lawme    Posted: 2005-12-02 11:57    Length: 2,852 byte(s)
[Original] [Print] [Top]
  多谢版主帮助,抽出空来一定学学wiki。

  三、创建 client 的套路

  第二节说到的两个类,是TCP协议客户端的创建套路(方式)。这个套路拆解如下:

  1、定义“工厂”和“协议”两个类:

  (1)“协议”类是 CallbackAndDisconnectProtocol,“工厂”类是 ConnectionTestFactory

     类的名字不重要,但必须正确说明所继承的父类:

     class CallbackAndDisconnectProtocol(protocol.Protocol)

     class ConnectionTestFactory(protocol.ClientFactory)

  (2)“协议”类是“工厂”类实例化的:protocol = CallbackAndDisconnectProtocol;

  (3)只在“工厂”类中有 __init__ 函数,并在其中实例化一个deferred 对象:

     self.deferred = defer.Deferred( )

  (4)在“工厂”类中,重设父类函数 clientConnectionFailed,通过deferred 引发事件,报告连接失败:

     self.deferred.errback(reason)     

  (5)在“协议”类中,重设父类函数 onnectionMade,由对象factory引用“工厂”类中的deferred,经其引发事件,报告连接正常:

     self.factory.deferred.callback("Connected!")

  并由对象transport引发事件,报告连接断开:

     self.transport.loseConnection( );

  上述“对象”,都是从各自父类继承来的。


  2、在函数testConnect(host, port)中,

  (1)将“工厂”类实例化:testFactory = ConnectionTestFactory( )

  (2)由全局循环“主持人”reactor建立以testFactory为“主演”的TCP连接:

     reactor.connectTCP(host, port, testFactory)

  (3)返回deferred对象:return testFactory.deferred


  至此,一个以事件驱动为基础、异步执行任务的框架程序搭成了。

  上述三节的内容,据 Twisted 官方说,是“学习曲线最陡”的部分(They represent the steepest part of the

Twisted learning curve.)。

  我的感受,造成“最陡”的原因,是由于套路新颖独特,初学乍练不易适应。

  1、框架对象众多,一时记不牢;

  2、对象之间的关系比较复杂,一时理不清;

  3、“事件驱动”这种模式,反映在程序文本中,有时见不到明显的函数调用,让人觉得程序的去向不明;

  另外,学习方法很重要。如果以学“语言”的习惯来学框架,遇上问题寻根究底,过分追求“水落石出”;或者,依赖教科书、畸重“理论”,忽视 examples 语句、结构和API文档的分析研究,都不利于翻越这段陡坡。
  
  据我的体验,集中精力地啃嚼主干骨架,不纠緾于细枝末节,这段最陡的上坡路,顶多爬个十天八天的,就能越过去。

[Original] [Print] [Top]
Subject: Re: 啃嚼Twisted的初感
Author: passworld    Posted: 2005-12-02 19:22    Length: 980 byte(s)
[Original] [Print] [Top]
Twisted 给我的印象一直是把简单的弄复杂了,复杂的还是那么复杂,大概所有framework都有这个特性吧。 所以一直没耐心看下去。你的这个介绍,终于让我知道它在干什么了。

def connectionMade(self) 里用到 self.factory ,不过从API里看不出这个factory是从那里来的。self.transport 倒是定义了。难道是buildProtocol里设定的?对:
"""
The returned instance will handle input on an incoming server connection, and an attribute "factory" pointing to the creating factory.
"""

感觉上介绍具体subclass之前把 protocol.Protocol 和 ClientFactory 自己的和继承来的方法介绍一下,似乎更容易理解。否则就这么直接看例子,实在是让我看得莫名其妙。

framework 实在是杀敌一千,自损八百,往往最后为了函盖所有功能,变得怪异无比。不是大玩艺是不能用的,大玩艺需要实现的功能又未必全能实现。


----
[Original] [Print] [Top]
Subject: Re: 啃嚼Twisted的初感
Author: panhudie    Posted: 2005-12-02 21:00    Length: 315 byte(s)
[Original] [Print] [Top]
这是我的理解:
先把protocol给factory
然后listenTCP
然后等select出这个socket
然后这个socket通知Port #Port在internet cp.py, 在listenTCP里面被instance
Port然后call factorty.buildProtocol
然后Port告诉protocol makeConnection
然后protocol告诉你 connectionMade
[Original] [Print] [Top]
Subject: Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-12-02 23:25    Length: 206 byte(s)
[Original] [Print] [Top]
  楼上两位朋友的意见、建议和看法很好,很受启发。

  再往下续写时,适当采纳二位的意见。

  很想及时听到大家的指导性意见。

  谢谢二位!
[Original] [Print] [Top]
Subject: Re: 啃嚼Twisted的初感
Author: lawme    Posted: 2005-12-07 00:19    Length: 5,359 byte(s)
[Original] [Print] [Top]
 
  四、创建 server 的套路

  网络程序,总得传送数据什么的。本节说说这事儿,一个玩具式的对话服务器。

  咱这儿说事儿,还是老套路,用例程说话。

  我是这样想的:框架这玩艺儿,是让咱比着葫芦画瓢使的,不必太在意葫芦为啥长成那般模样。自己试着例程跑得起来,自然这瓢是画对了,也不用管那模特葫芦的内瓤是啥名堂了。当然,尽量把葫芦内瓤搞清楚更好,画起瓢来心里更有底、更塌实吧。言归正传,画瓢开始。

from twisted.internet import reactor, protocol

class Talk(protocol.Protocol):

  def dataReceived(self, data):

    print "Client:",data

    if not data=='bye':
      s=''
      while(s==''):
        s=raw_input('Server: ')
        s=s.strip()
      self.transport.write(s)

def main():

  factory = protocol.ServerFactory()
  factory.protocol = Talk
  reactor.listenTCP(8000,factory)
  reactor.run()

if __name__ == '__main__':
  main()

  先来说说咱这“瓢”。

  1、服务器的构建启动:从调用函数 main() 开始,生成“工厂”对象factory,指定factory用的通讯“协议”为Talk,指定以端口8000和factory构成服务器,并启动它。

  2、服务器的运行:类Talk中的方法dataReceived,实际上是个event,当收到客户端传来的数据时,它做这几件事儿:
  (1)在显示器上写出:Client:和传来的数据;
  (2)如果传来的数据是字符串“bye”,不作处理。否则,屏显提示“Server:",要求键入一行字符;如果键入的不全是空格,将其传给客户端。

  再来看看“葫芦的内瓤”。

  1、为什么在程序中,没有“工厂”类。在protocol.py中定义的类ServerFactory是个空类,没有“方法”可以重设(注:protocol.py中各类的“方法”,基本上都是“事件”);其父类Factory中虽有方法可供重设,但本程序太简单用不着。

  在类Factory中,只有以下3个方法可以在程序文本中重设:

  (1)buildProtocol(self, addr),用以改变“工厂”类所用Protocal的创建方式;

  (2)startFactory(self),在factory开始监听连接前,仅调用一次。用于连接数据库、打开文件等操作;
  
  (3)stopFactory(self),用于关闭数据库、文件等操作。

  可否在程序文本中显式调用以上3个方法,protocol.py注释只明确说,不允许调用stopFactory。但从逻辑上,它们作为“事件”,应该只能重设不许直接调用。

  2、类Protocol的简单介绍

  它有2个方法用以重设:

  (1)dataReceived(self, data),当收到客户端传来的数据时,执行它。data是不定长字符串;

  (2)connectionLost(self, reason=connectionDone),当连接断开时,执行它;reason的类型是: L{twisted.python.failure.Failure}

  3、类Protocol父类 BaseProtocol 的简单介绍

   BaseProtocol 是各种网络协议的抽象父类。如果实现一个新协议加入Twisted,不管是客户端还是服务器端的协议,都应该以 BaseProtocol作为父类。

   BaseProtocol 的API很简单。在子类 Protocol 中实现了方法 dataReceived(data) ,处理基于事件和异步的输入;输出则由属性对象 'transport' 传送。'transport' 实现的是L{twisted.internet.interfaces.ITransport}。

  定义了二个方法,其中,可重设的是 connectionMade(self),当连接完成时,执行它。可以将其看作”协议“类的初始化方法。


  下面是客户端。它已是脸熟的老朋友了,但没用deferred,其他不用多说了吧。

from twisted.internet import reactor, protocol

class TalkClient(protocol.Protocol):

  def connectionMade(self):
    s=self.say()
    self.transport.write(s)

  def dataReceived(self, data):
    print "Server:", data
    s=self.say()
    self.transport.write(s)

    if s=='bye':
      self.transport.loseConnection()

  def connectionLost(self, reason):
    print "connection lost"
    from twisted.internet import reactor
    reactor.stop()

  def say(self):
    s=''
    while(s==''):
      s=raw_input('Client: ')
      s=s.strip()
    return s

class TalkFactory(protocol.ClientFactory):
  protocol = TalkClient

  def clientConnectionFailed(self, connector, reason):
    print "Connection failed - goodbye!"
    reactor.stop()

  def clientConnectionLost(self, connector, reason):
    print "Connection lost - goodbye!"
    reactor.stop()


def main():
  f = TalkFactory()
  reactor.connectTCP("localhost", 8000, f)
  reactor.run()

if __name__ == '__main__':

  f = TalkFactory()
  reactor.connectTCP("localhost", 8000, f)
  reactor.run()

[Original] [Print] [Top]
« Previous thread
pydoc tut里的一段话。 implementation of method不太明白。
Python 编 程
4
Next thread »
karrigell上传文件的怪问题
     

Copyright © 2007 UNIX Resources Network, All Rights Reserved.      About URN | Privacy & Legal | Help | Contact us
备案序号: 京ICP备05006143    webmaster: webmaster@unixresources.net
This page created on 2008-07-17 04:10:58, cost 0.060061931610107 ms.