使用 Twisted 应用程序框架

简介

受众

本文档的目标受众是希望以可重用、标准且易于配置的方式部署大量 Twisted 代码的 Twisted 用户。希望使用应用程序框架的 Twisted 用户需要熟悉开发 Twisted 服务器 和/或 客户端.

目标

  • 介绍 Twisted 应用程序基础设施。

  • 解释如何使用 .tac 文件和 twistd 部署 Twisted 应用程序。

  • 概述现有的 Twisted 服务。

概述

Twisted 应用程序基础设施负责运行和停止您的应用程序。使用此基础设施可以免去编写大量样板代码,方法是将您的应用程序挂钩到现有的工具,这些工具管理守护进程、日志记录、选择 Reactor 等等。

管理 Twisted 应用程序的主要工具是一个名为 twistd 的命令行实用程序。 twistd 是跨平台的,是运行 Twisted 应用程序的推荐工具。

Twisted 应用程序基础设施的核心组件是 twisted.application.service.Application() 对象 - 代表您的应用程序的对象。但是,Application 不会提供任何您想直接操作的内容。相反,Application 充当应用程序提供的任何“服务”(实现 IService 的对象)的容器。您与 Application 基础设施的大部分交互将通过服务完成。

“服务”是指应用程序中可以启动和停止的任何内容。典型的服务包括 Web 服务器、FTP 服务器和 SSH 客户端。您的 Application 对象可以包含许多服务,甚至可以使用 MultiService 或您自己的自定义 IServiceCollection 实现来包含服务的结构化层次结构。您很可能希望使用它们来管理依赖于其他服务的服务。例如,代理 Twisted 应用程序可能希望其服务器服务仅在关联的客户端服务启动后才启动。

一个 IService 具有两个基本方法,startService() 用于启动服务,stopService() 用于停止服务。后者可以返回一个 Deferred,表示服务关闭尚未完成,直到结果触发。例如

from twisted.internet import reactor
from twisted.application import service
from somemodule import EchoFactory

class EchoService(service.Service):
    def __init__(self, portNum):
        self.portNum = portNum

    def startService(self):
        self._port = reactor.listenTCP(self.portNum, EchoFactory())

    def stopService(self):
        return self._port.stopListening()

有关 EchoFactorylistenTCP 的解释,请参见 编写服务器

使用服务和应用程序

twistd 和 tac

为了处理 Twisted 应用程序的启动和配置,Twisted 应用程序基础设施使用 .tac 文件。 .tac 是 Python 文件,用于配置一个 Application 对象并将此对象分配给顶层变量“application”。

以下是一个简单的 .tac 文件示例

service.tac

# You can run this .tac file directly with:
#    twistd -ny service.tac

"""
This is an example .tac file which starts a webserver on port 8080 and
serves files from the current working directory.

The important part of this, the part that makes it a .tac file, is
the final root-level section, which sets up the object called 'application'
which twistd will look for
"""

import os

from twisted.application import internet, service
from twisted.web import server, static


def getWebService():
    """
    Return a service suitable for creating an application object.

    This service is a simple web server that serves files on port 8080 from
    underneath the current working directory.
    """
    # create a resource to serve static files
    fileServer = server.Site(static.File(os.getcwd()))
    return internet.TCPServer(8080, fileServer)


# this is the core part of any tac file, the creation of the root-level
# application object
application = service.Application("Demo application")

# attach the service to its parent application
service = getWebService()
service.setServiceParent(application)

twistd 是一个程序,它使用 .tac 文件运行 Twisted 应用程序。在最简单的形式中,它接受一个参数 -y 和一个 tac 文件名。例如,您可以使用命令 twistd -y service.tac 运行上述服务器。

默认情况下,twistd 会守护进程并记录到名为 twistd.log 的文件中。更常见的是,在调试时,您希望应用程序在前景运行并将日志记录到命令行。要像这样运行上述文件,请使用命令 twistd -noy service.tac

有关更多信息,请参见 twistd 手册页。

自定义 twistd 日志记录

twistd 的日志记录可以通过命令行进行自定义。这需要一个可导入的 *日志观察器工厂*。假设有一个名为 my.py 的文件,其中包含以下代码

from twisted.logger import textFileLogObserver

def logger():
    return textFileLogObserver(open("/tmp/my.log", "w"))

调用 twistd --logger my.logger ... 将把日志记录到名为 /tmp/my.log 的文件中(这个简单的示例可以很容易地用 --logfile 参数替换)。

或者,可以通过 .tac 文件中可访问的 API 来自定义日志记录行为。 ILogObserver 组件可以设置在应用程序上,以自定义 twistd 将使用的默认日志观察器。

以下是如何使用 DailyLogFile 的示例,它每天轮换一次日志。

from twisted.application.service import Application
from twisted.logger import ILogObserver, textFileLogObserver
from twisted.python.logfile import DailyLogFile

application = Application("myapp")
logfile = DailyLogFile("my.log", "/tmp")
application.setComponent(ILogObserver, textFileLogObserver(logfile))

调用 twistd -y my.tac 将在 /tmp/my.log 创建一个日志文件。

Twisted 提供的服务

Twisted 还为常见情况(如监听 TCP 端口)提供了预先编写的 IService 实现,位于 twisted.application.internet 模块中。以下是一个构建在 TCP 端口 7001 上运行回声服务器的服务的简单示例

from twisted.application import internet, service
from somemodule import EchoFactory

port = 7001
factory = EchoFactory()

echoService = internet.TCPServer(port, factory) # create the service

这些服务中的每一个(除了 TimerService)在反应器上都有一个相应的“连接”或“监听”方法,并且服务的构造函数接受与反应器方法相同的参数。“连接”方法用于客户端,“监听”方法用于服务器。例如,TCPServer 对应于 reactor.listenTCPTCPClient 对应于 reactor.connectTCP

TCPServer

TCPClient

允许您在 TCP 端口上建立连接和监听连接的服务。

UNIXServer

UNIXClient

在 UNIX 套接字上监听和建立连接的服务。

SSLServer

SSLClient

允许您建立 SSL 连接和运行 SSL 服务器的服务。

UDPServer

允许您通过 UDP 发送和接收数据的服务。

另请参阅 UDP 文档

UNIXDatagramServer

UNIXDatagramClient

在 UNIX 数据报套接字上发送和接收数据的服务。

MulticastServer

支持多播的 UDP 套接字方法的服务器。

TimerService

定期调用函数的服务。

服务集合

IServiceCollection 对象包含 IService 对象。可以通过调用 setServiceParent 将 IService 对象添加到 IServiceCollection,并使用 disownServiceParent 将其分离。

IServiceCollection 的标准实现是 MultiService,它也实现了 IService。MultiService 用于创建一个新的服务,该服务组合了两个或多个现有服务。例如,您可以创建一个 DNS 服务作为 MultiService,它有两个子服务:TCP 服务和 UDP 服务。

from twisted.application import internet, service
from twisted.names import server, dns, hosts

port = 53

# Create a MultiService, and hook up a TCPServer and a UDPServer to it as
# children.
dnsService = service.MultiService()
hostsResolver = hosts.Resolver('/etc/hosts')
tcpFactory = server.DNSServerFactory([hostsResolver])
internet.TCPServer(port, tcpFactory).setServiceParent(dnsService)
udpFactory = dns.DNSDatagramProtocol(tcpFactory)
internet.UDPServer(port, udpFactory).setServiceParent(dnsService)

# Create an application as normal
application = service.Application("DNSExample")

# Connect our MultiService to the application, just like a normal service.
dnsService.setServiceParent(application)