Twisted是用Python实现的基于事件驱动的网络引擎框架,功能非常丰富,基本包括了常用的网络组件。
所谓事件驱动,就是说程序就像是一个报警器(reactor),时刻等待着外部事件(event),诸如有人入侵等,一旦有事件发生,程序就会触发一些特定的操作(callback),注入拨打报警电话等。
Reactor
reactor是twisted框架中的核心,负责管理各种回调函数,接收各种系统事件,并根据规则对事件和回调函数进行匹配、派发处理。在Linux系统中,由于秉承“一切皆文件”的理念,系统中的事件主要就是文件事件以及定时事件。其实大多使用了不同系统中特定的API,具体来说,Linux上默认是epoll,OS X默认是Poll,其他系统默认都是select,每个API都会有一个特定的reactor与之对应。
从代码上来看,每当你import twisted.internet.reactor时,他就会根据当前系统返回特定的reactor module(twisted/twisted/internet/default.py),然后调用特定reactor module的install()函数。这里我们看一下对应Linux系统的epollreactor的install函数
# twisted/twisted/internet/epollreactor.pydef install(): """ Install the epoll() reactor. """ p = EPollReactor() from twisted.internet.main import installReactor installReactor(p)#twisted/twisted/intenet/main.pydef installReactor(reactor): """ Install reactor C{reactor}. @param reactor: An object that provides one or more IReactor* interfaces. """ # this stuff should be common to all reactors. import twisted.internet import sys if 'twisted.internet.reactor' in sys.modules: raise error.ReactorAlreadyInstalledError("reactor already installed") twisted.internet.reactor = reactor sys.modules['twisted.internet.reactor'] = reactor
代码是非常清楚的,就是创建了一个EPollReactor的实例,然后使用sys.module[""] = reactor将其注册为默认的reactor,这也就是使用twisted编程时不需显示创建reactor的原因。
究竟一个reactor到底干了些什么呢?twisted在这一块为了抽象以及扩展性,写了大量的类,用了大量的继承,但是简单来说,最终会落回到EPollReactor的doPoll函数中。
def doPoll(self, timeout): """ Poll the poller for new events. """ if timeout is None: timeout = -1 # Wait indefinitely. try: # Limit the number of events to the number of io objects we're # currently tracking (because that's maybe a good heuristic) and # the amount of time we block to the value specified by our # caller. l = self._poller.poll(timeout, len(self._selectables)) except IOError as err: if err.errno == errno.EINTR: return # See epoll_wait(2) for documentation on the other conditions # under which this can fail. They can only be due to a serious # programming error on our part, so let's just announce them # loudly. raise _drdw = self._doReadOrWrite for fd, event in l: try: selectable = self._selectables[fd] except KeyError: pass else: log.callWithLogger(selectable, _drdw, selectable, fd, event)
其中的self._poller通过epoll就是一个epoll调用的返回值,简单点说,也就是一个典型的epoll应用场景,在timeout时间内,检查需要处理的事件,然后通过log.callWithLogger调用相关的回调函数。
Transport
用于抽象通信双方之间的链接(TCP、UDP等),通过它可以向对方发送数据,获取对方信息等。
Protocol
用于抽象双方的通信协议,包括如何建立链接、处理数据以及出错处理等接口。一个类实现了这些接口,就等于定义了一个新的协议,twisted自带的协议非常多,一般情况下不需要自定义协议,除非你有特殊要求。
Protocol Factory
熟悉设计模式的应该对factory不陌生,简单来说,这个类定义了一个接口buildProtocol,用于返回一个Protocl实例(但是通常的做法是在factory类中使用类成员protocol来注册响应的Protocol),同时在这个类里你可以保存一些数据,用于配置或者管理系统中所有的Protocol实例。
简单的Echo服务器程序
# Serverfrom twisted.internet import protocol, reactorclass Echo(protocol.Protocol): def dataReceived(self, data): self.transport.write(data)class EchoFactory(protocol.Factory): def buildProtocol(self, addr): return Echo()reactor.listenTCP(8080, EchoFactory())reactor.run()# Clientfrom twisted.internet import protocol, reactorclass EchoClient(protocol.Protocol): def connectionMade(self): self.transport.write("Hello, world!") def dataReceived(self, data): self.transport.loseConnection()class EchoFactory(protocol.ClientFactory): def buildProtocol(self, addr): return EchoClient() def clientConnectionFailed(self, connector, reason): reactor.stop() def clientConnectionLost(self, connector, reason): reactor.stop()reactor.connectTCP("localhost", 8080, EchoFactory())reactor.run()