Twisted
Twisted定义
Twisted是一个基于事件驱动的网络引擎框架
网络框架,别人预先定义好的一个框架(一个项目),如.net某个web框架有25个class,从BeginRequest依次执行类里的process方法,程序员自己定义一个类,添加到框架里,应用程序从上到下运行,就会执行自定义代码。框架只知道这个类的列表,不关心你写了什么内容,从上到下执行,类似于一个执行链,C#里叫委托链。也就是把代码类放到这个列表中,委托这个框架替你执行。
事件驱动(not event),把自定义代码注册到框架中,框架代替你执行。或者框架提供几个接口,让你插入数据(python里没有 )。
委托不能为空,事件可以为空。
演示一个最简单的框架
前期准备:
新建一个名为event_drive的python package,里面新建一个event_drive.py文件,这个就是框架主文件,把package目录复制到sys.path中,如:c:\python27\lib\site-package\
event_drive.py:
1 2 3 4 5 6 7 8 9 10 11 12 13 | event_list = [] #[myclass,] def run(): for event in event_list: obj = event() obj.execute() class BaseHandler( object ): """ 用户必须继承该类,从而规范所有类的方法(类似于接口的功能) """ def execute( self ): raise Exception( 'you must overwrite execute' ) |
自定义代码:
1 2 3 4 5 6 7 8 9 | from event_drive import event_drive class MyClass(event_drive.BaseHandler): def execute( self ): #重写execute方法 print "执行了自定义execute方法" event_drive.event_list.append(MyClass) #注册到委托链即“注册一个事件” event_drive.run() |
执行过程:
导入event_drive文件夹中的event_drive文件
自定义一个类MyClass,这个类继承了event_drive文件中BaseHandler类
类里实现execute方法,内容无所谓甚至可以为空,方法名称execute不能改变
注册事件到框架的委托链,即把类名list.append(MyClass)传进去(下面的Twisted框架是创建对象后改一个字段为类名也是同样的目的)
执行run方法,框架自己就把MyClass中的方法执行了
执行结果:
1 2 | 执行了自定义execute方法 Process finished with exit code 0 |
Twisted框架:以socket为例
安装Twisted:(linux参考如下,windows直接用安装包)
1 2 3 | cd Twisted-15.5.0 python setup.py build python setup.py install |
ps:twisted调用了zope和win32api模块,先安装这两个,要不会报错。
Twisted_server.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | from twisted.internet import reactor, protocol from twisted.web.client import getPage from twisted.internet import reactor import time class Echo(protocol.Protocol): #继承protocol.py中的Protocol类 def dataReceived( self , data): self .transport.write(data) #将收到的内容直接发送回去 factory = protocol.ServerFactory() #实例化 factory.protocol = Echo #将自定义类传给对象 reactor.listenTCP( 8000 ,factory) #将端口和实例化对象作为参数传给reactor reactor.run() |
Twisted_client.py
1 2 3 4 5 6 7 8 9 10 11 12 | import socket ip_port = ( '127.0.0.1' , 8000 ) sk = socket.socket() sk.connect(ip_port) sk.settimeout( 5 ) while True : inp = raw_input ( "please input:" ) sk.sendall(inp) print sk.recv( 1024 ) sk.close() |
执行原理
跟SocketServer原理类似,内部封装,内部有一个while循环,while循环一旦触发,找到这个类,执行这个类的构造方法,创建对象,通过对象,执行预定义的方法,
源码分析
程序执行流程:
- 运行服务端程序
创建Protocol的派生类Echo
解释:自定义Echo类,名字随便起,它继承了Protocol类,Protocol类又继承了BaseProtocol类,有了最左边的图
创建ServerFactory对象,并将Echo类封装到其protocol字段中
解释:ServerSocket是将MyClass以参数的形式封装,这个是以字段的形式
执行reactor的 listenTCP 方法,内部使用 tcp.Port 创建socket server对象,并将该对象添加到了 reactor的set类型的字段 _read 中
解释:
print type(reactor)
==>
<class 'twisted.internet.selectreactor.SelectReactor'>
去selectreactor.SelectReactor中找listenTCP,看上面的类继承关系图,继承了好多类。listenTCP和run方法都在基类里。
def listenTCP(self, port, factory, backlog=50, interface=''):
p = tcp.Port(port, factory, backlog, interface, self)
p.startListening()
return p
其中把factory对象传入,就相当于:1、把Echo类封装到factory字段2、再把factory对象封装到listenTCP3、tcp.port里创建了socket连接执行reactor的 run 方法,内部执行 while 循环,并通过 select 来监视 _read 中文件描述符是否有变化,循环中...
解释:SelectReactor中包含两个集合_reads=set()和_writes=set(),不允许重复的集合,有连接后把文件句柄添加到这个集合中。开始执行reactor.run(),它调用基类里的mainLoop方法,又调取的selectreactor.doInteration,找不到?因为它是个重命名doInteration=doSelect,这个方法里面调取的就是select方法,通过调用select,循环这个_reads。一旦有句柄进来,通过反射去_reads里找“doRead”执行方法。
客户端请求到达
- 执行reactor的 _doReadOrWrite 方法,其内部通过反射调用 tcp.Port 类的 doRead 方法,内部 accept 客户端连接并创建Server对象实例(用于封装客户端socket信息)和 创建 Echo 对象实例(用于处理请求) ,然后调用 Echo 对象实例的 makeConnection 方法,创建连接。
- 执行 tcp.Server 类的 doRead 方法,读取数据,
- 执行 tcp.Server 类的 _dataReceived 方法,如果读取数据内容为空(关闭链接),否则,触发Echo 的 dataReceived 方法
- 执行 Echo 的 dataReceived 方法
功能
Twisted主要用于网络操作,它支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。其中包含了诸多功能,例如:网络协议、线程、数据库管理、网络操作、电子邮件等。
优点
使用基于事件驱动的编程模型,而不是多线程模型。
跨平台:为主流操作系统平台暴露出的事件通知系统提供统一的接口。
“内置电池”的能力:提供流行的应用层协议实现,因此Twisted马上就可为开发人员所用。
符合RFC规范,已经通过健壮的测试套件证明了其一致性。
能很容易的配合多个网络协议一起使用。
可扩展。
一个非常全面介绍Twisted网站
http://twisted.readthedocs.org/en/twisted-15.5.0/