Twisted 框架介绍
Twisted 是一个完整的事件驱动的网络框架,利用它既能使用也能开发完整的异步网络应用程序和协议。
它现在还不是标准库的一部分,所以必须单独下载并安装它。使用pip install即可。
它提供了大量的支持来建立完整的系统,包括网络协议、线程、安全性和身份验证、聊天/ IM、 DBM 及RDBMS 数据库集成、 Web/因特网、电子邮件、命令行参数、 GUI 集成工具包等。
Twisted 提供了一个更加强大和灵活的框架,并且已经实现了很多协议。可以在
http://twistedmatrix.com 网站上找到更多关于 Twisted 的消息。
与 SocketServer 类似, Twisted 的大部分功能都存在于它的类中。
创建Twisted Reactor TCP 服务器
示例代码:
from twisted.internet import protocol, reactor
from time import ctime
PORT = 21567
class TSServProtocol(protocol.Protocol):
def connectionMade(self):
clnt = self.clnt = self.transport.getPeer().host
print('...connected from: {}'.format(clnt))
def dataReceived(self, data):
print('received from clinet: {}'.format(data.decode('utf-8')))
data_formated = '[{}] {}'.format(ctime(), data.decode('utf-8'))
self.transport.write(data_formated.encode('utf-8'))
factory = protocol.Factory()
factory.protocol = TSServProtocol
print('waiting for connection...')
reactor.listenTCP(PORT, factory)
reactor.run()
获得protocol类并为时间戳服务器调用TSServProtocol。然后重写了connectionMade()和dataReceived()方法,当一个客户端连接到服务器时就会执行connectionMade()方法,而当服务器收到客户端通过网络发送的一些数据时,就会调用dataReceived()方法。reactor会作为该方法的一个参数在数据中传输,这样就能在无需自己提取它的情况下访问它。
此外, 传输实例对象解决了如何与客户端通信的问题。可以看到这个例子里如何在connectionMade()中使用它来获取主机信息,这些是关于与我们进行连接的客户端的信息,以及如何在dataReceived()中将数据返回给客户端。
在服务器代码的最后一部分,创建了一个协议工厂。之所以被称为工厂,是因为每次得到一个接入连接时,都能“制造”协议的一个实例。然后在ractor中安装一个TCP监听器,以此检查服务请求。当它接收到一个请求时,就会创建一个TSServProtocol实例来处理那个客户端的事务。
创建Twisted Reactor TCP 客户端
示例代码:
from twisted.internet import protocol, reactor
HOST = 'localhost'
PORT = 21567
class TSClntProtocol(protocol.Protocol):
def sendData(self):
data = input('> ')
if data:
print('sending {}'.format(data))
self.transport.write(data.encode('utf-8'))
else:
self.transport.loseConnection()
def connectionMade(self):
self.sendData()
def dataReceived(self, data):
print(data.decode('utf-8'))
self.sendData()
class TSClntFactory(protocol.ClientFactory):
protocol = TSClntProtocol
clientConnectionLost = clientConnectionFailed = lambda self, connector, reason: reactor.stop()
reactor.connectTCP(HOST, PORT, TSClntFactory())
reactor.run()
在客户端的代码中,也是通过重写connectionMade()和dataReceived()方法来扩展Protocol,并且这两者都会以与服务器相同的原因来执行。另外,还添加了自己的方法sendData(), 当需要发送数据时就会调用它。
因为是客户端,所以是开启与服务器对话的一端。一旦建立了连接,就进行第一步,即发送一条消息。服务器回复之后,我们将接受到的消息显示在屏幕上,并向服务器发送另一个消息。
以上行为会在一个循环中继续,直到当提示输入时我们不输入任何内容来关闭连接。此时,并非调用传输对象的write()方法发送另一个消息到服务器,而是执行loseConnection()来关闭套接字。当发生这种情况时,将调用工厂的 clientConnectionLost() 方法以及停止ractor,结束脚本执行。此外,如果因为某些其他的原因而导致系统调用了clientConnectionFailed(), 也会停止ractor.
在脚本最后创建了一个客户端工厂,创建一个到服务器的连接并运行ractor. 注意,这里实例化了客户端工厂,而不是将其传给reactor。这是因为我们不是服务器,需要等待客户端的连接,且服务器的工厂需要为每一次的连接都创建一个新的协议对象。我们这里是一个客户端,所以创建单个连接到服务器的协议对象。