第一章 介绍Twisted
1.1 开始
在你会用Twisted建立app之前,你需要下载安装Twisted和它的环境。这一章的主要任务就是帮助你学会安装Twisted。
Twisted需要python2.6或者2.7。支持python3的版本还在构建中。
安装Twisted
首先:你需要下载Twisted。下载和说明以及相应的版本都可以在https://twistedmatrix.com/trac/找到(建议各位去官网看看)。想要启动Twisted里面的其他功能,你需要安装一些额外的包。
linux上安装
所有流行的Linux发布版本都内置了一个python-twisted安装包和对应版本的环境支持。如果要在dpkg-based系统上安装,用
apt-get install python-twisted
正在rmp-based系统,用
yum install python-twisted
就这么简单。
如果你要使用Twisted的SSL或者SSH功能,可以用python-openssl和python-crypto来获取。
Windows上安装
Twisted对于Windows有32位和64位,如果你不确定,就安装32位的。
去官网上下载Twisted吧https://twistedmatrix.com/trac/。
测试你的Twisted
为了验证你的Twisted没有损坏,在python下这样写
import twisted print(twisted.__version__)
验证你已经安装了pyOpenSSL来使用Twisted的SSL功能,用以下代码测试
import OpenSSL import twisted.internet.ssl twisted.internet.ssl.SSL
如果你没有看到报错,你已经成功地为你的Twisted添加了SSL支持。
如果你为了使用Twisted的SSH已经安装了PyCrypto,可以这样验证
import Crypto import twisted.conch.ssh.transport twisted.conch.ssh.transport.md5
如果没有看到错误就一切OK。
恭喜你,你已经知道了怎么安装Twisted开始你的编程之路了。
1.2建立一个基础的客户端和服务器
学习Twisted应用的最好方法就是实践一些小例子。这一章会为你介绍reactor循环,信息传输和在客户端服务器上执行TCP协议。
A 基于TCP的回显客户端和服务器
请浏览一下examples2-1和2-2。服务器建立了TCO连接而且监听了固定端口,而且为它受到的所有信息进行回显。客户端负责连接服务器,发送消息,接受回应和断开连接。
#Example 2-1 echoserver.py
from twisted.internet import protocol,reactor
class Echo(protocol.Protocol):
def dataReceived(self, data):
print('receive: ',data)
self.transport.write(data)
class EchoFactory(protocol.Factory):
def buildProtocol(self, addr):
print('addr:',addr)
return Echo()
reactor.listenTCP(8001,EchoFactory())
reactor.run()
#Example 2-2 echoclient.py
from twisted.internet import reactor,protocol
class EchoClient(protocol.Protocol):
def connectionMade(self):
print('send msg')
self.transport.write(b"Hello,world!")
def dataReceived(self, data):
print('receive msg:',data)
self.transport.loseConnection()
class EchoClientFactory(protocol.ClientFactory):
def buildProtocol(self, addr):
return EchoClient()
def clientConnectionLost(self, connector, reason):
print("conn lost")
reactor.stop()
def clientConnectionFailed(self, connector, reason):
print('conn failed')
reactor.stop()
reactor.connectTCP("127.0.0.1",8001,EchoClientFactory())
reactor.run()
为了测试这两个脚本,首先在命令行里运行echoserver.py。这样就会在本地8001端口上运行一个TCP服务。之后在第二个命令行里运行echoclient.py。
addr: IPv4Address(type='TCP', host='127.0.0.1', port=61264) receive: b'Hello,world!' send msg receive msg: b'Hello,world!' conn lost
啊哈,你已经完成了你的第一个异步事件驱动的Twisted应用。让我们看看它的每一步的具体实现是怎样的吧。
事件驱动程序
回显服务器和客户端都是事件驱动程序,更流行的说法是,Twistd是一个异步驱动引擎,这是什么意思呢?
在一个异步驱动程序里,程序运行由外部事件驱动。最明显的特征是每当事件来临通过一个loop循环和使用callback来触发行为。把这个结构和其他两种相同的模型相比:单线程和多线程。
通过执行任务来显示三个模型的不同。程序有三个任务需要完成,每一个任务都需要等待IO结束,在这之前会阻塞。
在单线程里,任务是线性执行的。如果一个任务阻塞,所有的人物都必须等待,这显然是糟糕的方法。
在多线程里,三个阻塞任务在三个线程里执行,可以在一个或者多个处理器上运行。这样允许一些线程阻塞,另一些运行,显然比单线程有效率。然而,必须编写代码维护多个线程并发访问共享资源,否则会出现一些莫名其妙的BUG。
异步版本把三个任务交叉在一个线程内,在执行IO或者其他耗时的操作时,会通过loop回调注册的事件,在IO完成的时候继续执行。事件云鬟轮询事件,并且在事件来临的时候分发给等待着他们的回调函数。这允许程序在不使用额外线程的情况下取得进展。
异步驱动同时享受了多线程的并行和单线程的简单操作。
Reactor反应堆
Twisted的核心其实就是反应堆事件轮询。reactor知晓网络,文件系统和计时器的事件。它会等待并且分发这些事件给相应的处理器。Twisted负责把特定的行为抽象化,并且正确地使用底层的非阻塞API。Twisted存在一个通用接口来让网络堆栈中任何位置的事件很容易地获得相应。
reactor本质
while True: timeout=time_until_next_timed_event() events=wait_for_events(timeout) events+=timed_events_until(now()) for event in events: event.process()
在我们上边编写的客户端和服务器中,reactor通过监听TCP和连接TCP来负责注册回调,以便在8001端口上可以从TCP套接字读取数据时候得到通知。
在这些回调被注册之后,我们开始了反应堆的事件循环reactor.run()。一旦开始,reactor就会调度事件一直到得到反映或者一直运行下去,除非你stop它。
Transports通信
一个transport代表着网络两端的连接。Transports展示了连接的细节:举个例子,这是面向tcp,udp,unix套接字换你是串行接口的实例?Transports执行了ITransport接口,它有以下方法:
write
以非阻塞的方式把数据写入物理连接
writeSequence
以字符串列表的方式写入物理连接。在使用面向行的协议的时候有效。
loseConnection
写入所有数据,之后断开连接
getPeer
获得连接端的地址
getHost
和getPeer一样,但是返回的是本地的地址
在回显的例子里,两端发送数据用了write方法。客户端在接受到消息之后终止了链接。
Protocols
protocols展现了怎样异步运行程序。Twisted内置了许多流行的协议,包括HTTP,TELNET,DNS,IMAP。协议执行了IProtocol接口,它有以下方法:
makeConnection
通过两端的传输创建一个连接
connectionMade
连接到另一个端点的时候调用
dataReceived
接收到数据的时候调用
connectionLost
断开连接的时候调用
在我们的回显例子里用了protocol.Protocol作为基类。connectTCP创建了一个TCP连接而且为接收数据注册了回调方法。
Protocol Factories
持久性的数据被保存在工厂里,它继承protocol.Factory或者ClientFactory。里边的buildrotocol方法为每一个新的连接创建一个协议,而且被注册到reactor里边。
对工厂和协议的解耦让一个类型的transport拥有许多协议成为可能,而且便于测试。