接口与协议

Twisted内部有许多被称作接口的子模块,每个子模块都定义了一组接口类。使用接口的目的主要是使应用文档化,并且充分利用了Python「鸭子类型」的特征。Reactor根据其所支持的操作系统和特性的不同,部分或全部实现了以下接口来实现相应的功能。

  • IReactorCore,核心功能,提供Reactor启动、终止、异常处理等功能。
  • IReactorFDSet,提供Reactor使用文件描述符的功能,允许向Reactor添加实现了IReadDescriptor接口的Reader类实例来从连接读取数据或者添加实现了IWriteDescriptor接口的Writer类实例来向连接写入数据。
  • IReactorProcess,提供进程管理功能。
  • IReactorSSL,提供支持网络SSL功能。
  • IReactorTCP,提供支持网络TCP通讯的功能,允许Reactor监听TCP连接或者连接到TCP服务器。Reactor通过协议和协议工厂来处理数据。
  • IReactorThreads,提供线程控制功能。
  • IReactorTime,提供定时任务功能,允许部署一些定期任务。
  • IReactorUDP,提供支持网络UDP功能,允许Reactor监听UDP连接。
  • IReactorUNIX,提供支持UNIX套接字功能。
  • IReactorSocket,提供第三方套接字支持。

不止Reactor是由众多的接口组合起来的,整个Twisted框架都是由众多抽象层松散的组合起来的。因此要了解和使用Twisted框架必须了解每个抽象层都提供了哪些API,有哪些接口和实例可以使用。Reactor所实现的接口都属于比较低层级的接口,在实际应用中除非应用的需求必要,不会选择直接使用低层级接口来实现应用逻辑,而是通过高层级抽象层来实现。几乎所有的高层级抽象都是在低层级抽象的基础上建立的,并且高层级抽象不会重复实现低层级抽象已经实现的功能,而是通过继承和组合来获取已经实现的功能。

在常见的Twisted应用中,很少会直接和Reactor的API进行交互,但是请记住Reactor的存在。

在Twisted框架中,还有三个概念需要了解:传输、协议和协议工厂。

传输

twisted.interfaces中的ITransport接口定义,表示一个可以收发字节的单条连接。ITransport几乎总是在低层级抽象中完成异步数据读写的操作,然后通过回调将数据发送给我们的应用。通常在编写Twisted应用时不会自行实现ITransport接口,而是使用Twisted提供的实现。

协议

twisted.interfaces中的IProtocol接口定义,表示一个具体网络协议的实现,例如FTP、IMAP等。每一个Twisted的协议类都为一个具体的连接提供协议解析,所以应用每建立一条连接都需要一个协议实例,也就是说协议是存储协议状态、间断性接收数据并积累数据的地方。每个协议都会有一个makeConnection(ITransport)函数用来确定协议实例所要使用的连接。Twisted已经实现了许多的通用协议,大多都存放在twisted.protocols中。

协议工厂

由于每个连接都需要使用自己的协议实例,所以协议实例是需要根据连接动态创建的。Twisted需要通过一种方式来为连接创建合适的协议,这种方式就是协议工厂的工厂模式。协议工厂由twisted.interfaces中的IProtolcolFactory接口定义。Twisted利用协议工厂中的buildProtocol()方法来返回一个新的协议实例。在日常定义协议工厂时,通常会采用继承twisted.internet.protocol.Factory基类的方式来实现工厂类。Factory基类中已经实现了buildProtocol()这一方法,所以我们需要将要实现的协议类赋予类变量protocol以通知基类创建何种协议实例,buildProtocol()会根据这个类变量来创建相应的协议实例。

在创立协议实例后,协议工厂即可通过makeConnection()方法将协议与传输实例进行绑定。在绑定传输实例后,协议即可通过dataReceived()等方法来翻译数据。

当传输实例关闭时,就会激活connectionLost()方法,这个方法可以接收一个twisted.python.failure.Failure实例来说明连接关闭的原因。Failure实例对象可以用来传递给回调函数,用来捕获异常与跟踪栈。异常在Twisted的回调用可以使用一个独立的回调函数来处理。