##language:zh
#pragma section-numbers on
'''
开始TwistedStudyRecord写作
'''
::-- LawMe [<<DateTime(2005-12-01T01:17:25Z)>>]
<<TableOfContents>>

''''' 开始Twisted学习写作 '''''

= 啃嚼Twisted的初感 =

啃嚼快一星期了,不再痛苦难受,逐渐尝出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 强制退出。

下面是一个例子:
{{{#!python
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."
}}}

== 二、提升效率的 deferred ==

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

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

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

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

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

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

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

请看下面的例子:

建议只关注'''有特殊注释'''的语句,它们反映了deferred的用法。涉及的两个class,是Twisted建立网络连接的固定套路,后面会专门说它。

{{{#!python
# 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( )
}}}