Introdução ao Python Twisted

Link original: http://www.aosabook.org/en/twisted.html

Autor: Jessica McKellar

Twisted é uma estrutura de mecanismo de rede orientada a eventos implementada em Python. A Twisted nasceu no início de 2000. Aos olhos dos desenvolvedores de jogos online da época, não importa qual linguagem eles usem, eles raramente têm uma biblioteca de rede que possa ter escalabilidade e plataforma cruzada em suas mãos. Os autores do Twisted tentaram desenvolver jogos no ambiente existente na época. Essa etapa foi muito difícil. Eles precisavam com urgência de uma estrutura de desenvolvimento da web multiplataforma, altamente escalonável e orientada a eventos, então decidiram implementar uma por conta própria. E aprenda com os desenvolvedores de jogos e aplicativos da web anteriores e tire suas lições.

Twisted oferece suporte a muitos protocolos comuns de transmissão e camada de aplicativo, incluindo TCP, UDP, SSL / TLS, HTTP, IMAP, SSH, IRC e FTP. Assim como o Python, o Twisted também possui o recurso "baterias incluídas". O Twisted tem implementações de cliente e servidor para todos os protocolos que suporta, bem como ferramentas baseadas em linha de comando, tornando muito conveniente configurar e implantar aplicativos Twisted em nível de produto.

21.1 Por que o Twisted é necessário

Em 2000, Glyph, o autor de Twisted, estava desenvolvendo um jogo online multiplayer baseado em texto chamado Twisted Reality. Este jogo é desenvolvido em Java e há vários threads nele - cada conexão tem 3 threads para processar. A entrada de processamento de thread será bloqueada em operações de leitura, a saída de processamento de thread será bloqueada em algumas operações de gravação e uma thread "lógica" será interrompida quando o cronômetro de espera expirar ou o evento for colocado na fila. À medida que os jogadores se movem e interagem no mundo virtual, os threads ficam paralisados, o cache é contaminado e a lógica de bloqueio do programa quase nunca é correta - o uso de multi-threading torna todo o software complicado, cheio de lacunas e extremamente Extensão difícil.

Para encontrar outras soluções, o autor encontrou o Python, especialmente o módulo select usado para multiplexar E / S de objetos de streaming, como soquetes e tubos em Python (versão 3 da especificação UNIX (SUSv3) descreve select). Naquela época, o Java não fornecia a interface de seleção do sistema operacional ou qualquer outra API de E / S assíncrona (o pacote java.nio para E / S sem bloqueio foi adicionado no J2SE 1.4 e lançado em 2002). Usando o módulo select em Python para construir rapidamente um protótipo de jogo, isso reduz rapidamente a complexidade do programa e é mais confiável do que a versão multi-threaded.

A Glyph rapidamente se voltou para a programação Python, select e orientada a eventos. Ele usou o módulo select do Python para escrever o cliente e o servidor do jogo. Mas ele quer mais do que isso. Fundamentalmente, ele espera transformar o comportamento da rede em chamadas de métodos para objetos no jogo. E se você pudesse receber e-mails no jogo, como um daemon como o Nethack mailer? E se cada jogador do jogo tiver uma página inicial? Glyph descobriu que precisava de excelentes implementações de cliente e servidor de IMAP e HTTP em Python, e elas devem usar select.

Ele primeiro recorreu ao Medusa, uma plataforma desenvolvida em meados dos anos 90, onde o módulo asyncore em Python pode ser usado para escrever serviços de rede. asyncore é um módulo que processa soquetes de forma assíncrona e constrói um planejador e uma interface de retorno de chamada no topo da API selecionada do sistema operacional.

  1. Esta é uma descoberta empolgante para Glyph, mas Medusa tem duas desvantagens:
  2. Este projeto não foi mais mantido em 2001, e foi quando o glyph desenvolveu o Twisted Reality.

Asyncore é apenas uma fina camada de encapsulamento para sockets, e os escritores de aplicativos ainda precisam manipular sockets diretamente. Isso significa que o fardo da portabilidade do programa ainda recai sobre o próprio programador. Além disso, ainda havia um problema com o suporte do asyncore para Windows naquela época, e Glyph esperava executar um cliente com uma interface gráfica de usuário no Windows.

Glyph precisa implementar uma plataforma de mecanismo de rede sozinho, e ele percebe que Twisted Reality abriu a porta para o problema, que é tão interessante quanto seu jogo.

Com o tempo, o jogo Twisted Reality evoluiu para a plataforma de mecanismo de rede Twisted. Ele pode fazer coisas que as plataformas de rede existentes em Python não podiam fazer no momento:

  • Use um modelo de programação orientado a eventos em vez de um modelo multithread.
  • Plataforma cruzada: fornece uma interface unificada para o sistema de notificação de eventos exposto por plataformas de sistema operacional convencionais.
  • Recurso de "bateria interna": fornece implementações populares de protocolo de camada de aplicativo, para que o Twisted esteja imediatamente disponível para os desenvolvedores.
  • Ele está em conformidade com as especificações RFC e provou sua consistência por meio de um conjunto de testes robusto.
  • Ele pode ser usado facilmente com vários protocolos de rede.
  • Escalável.

 

21.2 Visão geral da arquitetura torcida

Twisted é um mecanismo de rede orientado por eventos. Uma vez que o modelo de programação orientado a eventos ocupa uma posição importante na filosofia de design do Twisted, é necessário reservar um momento para revisar o que significa orientado a eventos.

A programação orientada a eventos é um paradigma de programação, em que o fluxo de execução do programa é determinado por eventos externos. Caracteriza-se por incluir um loop de eventos, quando ocorre um evento externo, um mecanismo de callback é utilizado para acionar o processamento correspondente. Dois outros paradigmas de programação comuns são a programação síncrona (single-threaded) e multi-threaded.

Vamos usar exemplos para comparar e contrastar modelos de programação single-threaded, multi-threaded e orientados a eventos. A Figura 21.1 mostra o trabalho realizado pelo programa nesses três modos ao longo do tempo. Este programa tem 3 tarefas a serem concluídas e cada tarefa bloqueia a si mesma enquanto espera por operações de E / S. O tempo gasto no bloqueio das operações de E / S foi marcado com uma caixa cinza.

Figura 21.1 Modelo de rosca

No modelo de sincronização de thread único, as tarefas são executadas sequencialmente. Se uma tarefa for bloqueada devido a E / S, todas as outras tarefas devem esperar até que sejam concluídas antes de poderem ser executadas em sequência. Essa ordem de execução clara e comportamento de serialização são fáceis de inferir. Se as tarefas não dependerem umas das outras, mas ainda precisarem esperar uma da outra, isso fará com que o programa diminua desnecessariamente a velocidade de execução.

Na versão multithread, essas 3 tarefas são executadas em threads separadas. Esses threads são gerenciados pelo sistema operacional e podem ser processados ​​em paralelo em um sistema com vários processadores ou intercalados em um sistema com um único processador. Isso permite que outros encadeamentos continuem a execução enquanto um determinado encadeamento está bloqueado em um determinado recurso. Comparado com um programa síncrono que executa funções semelhantes, este método é mais eficiente, mas o programador deve escrever código para proteger recursos compartilhados e evitar que sejam acessados ​​por vários threads ao mesmo tempo. Programas multi-threaded são mais difíceis de inferir, porque tais programas têm que lidar com problemas de segurança de thread por meio de mecanismos de sincronização de thread, como bloqueios, funções reentrantes, armazenamento local de thread ou outros mecanismos. A implementação inadequada levará a erros sutis e indesejáveis.

Na versão orientada a eventos do programa, as três tarefas são executadas de maneira escalonada, mas ainda são controladas por um único encadeamento. Ao lidar com E / S ou outras operações caras, registre um retorno de chamada para o loop de eventos e continue a execução quando a operação de E / S for concluída. O retorno de chamada descreve como lidar com um evento. O loop de eventos pesquisa todos os eventos e os atribui à função de retorno de chamada que espera para processar o evento quando o evento chega. Desta forma, o programa pode ser executado tanto quanto possível, sem a necessidade de threads adicionais. Programas orientados a eventos são mais fáceis de inferir comportamento do que programas multithread, porque os programadores não precisam se preocupar com questões de segurança de thread.

Quando enfrentamos o seguinte ambiente, o modelo orientado a eventos geralmente é uma boa escolha:

  1. Existem muitas tarefas no programa e ...
  2. As tarefas são altamente independentes (portanto, não precisam se comunicar ou esperar um pelo outro) e ...
  3. Enquanto espera a chegada do evento, algumas tarefas serão bloqueadas.

Essa também é uma boa opção quando o aplicativo precisa compartilhar dados variáveis ​​entre tarefas, porque não há necessidade de sincronização.

Os aplicativos de rede geralmente têm essas características, o que os torna adequados para o modelo de programação orientado a eventos.

Reutilizar aplicativos existentes

Antes da criação do Twisted, havia muitas implementações de cliente e servidor para uma variedade de protocolos de rede populares. Por que a Glyph não usa Apache, IRCd, BIND, OpenSSH ou qualquer outro aplicativo existente diretamente, mas reimplementa o cliente e o servidor de cada protocolo para Twisted do zero?

O problema é que todas essas implementações existentes têm código de camada de rede escrito do zero, geralmente código C. O código da camada de aplicativo está diretamente acoplado à camada de rede, o que torna muito difícil reutilizá-los na forma de uma biblioteca. Quando você deseja usar esses componentes juntos, se deseja expor os mesmos dados em vários protocolos, eles devem ser visualizados na forma de uma caixa preta, o que não dá aos desenvolvedores a oportunidade de reutilizar o código. Além disso, as implementações de servidor e cliente geralmente são separadas e não compartilham código entre si. Para estender esses aplicativos, manter a compatibilidade cliente-servidor de plataforma cruzada não é tão difícil.

O cliente e o servidor no Twisted são desenvolvidos em Python e usam uma interface consistente. Isso facilita o desenvolvimento de novos clientes e servidores.Você pode compartilhar o código entre o cliente e o servidor, compartilhar a lógica do aplicativo entre os protocolos e testar o código de uma determinada implementação.

Modo reator

Twisted implementa o modo de reator no padrão de design, que despacha eventos gerados por várias fontes de eventos para suas respectivas rotinas de processamento de eventos em um ambiente de thread único.

O núcleo do Twisted é o loop de eventos do reator. O Reactor pode perceber eventos de rede, sistema de arquivos e temporizador. Ele espera e processa esses eventos, abstrai-os do comportamento específico da plataforma e fornece uma interface unificada, tornando mais fácil responder a eventos em qualquer lugar na pilha de protocolo de rede.

Basicamente, as tarefas realizadas pelo reator são:

while True:
    timeout = time_until_next_timed_event()
    events = wait_for_events(timeout)
    events += timed_events_until(now())
    for event in events:
        event.process()

O reator padrão atual do Twisted em todas as plataformas é baseado na API de pesquisa (descrita na terceira edição da especificação UNIX (SUSv3)). Além disso, o Twisted também oferece suporte a algumas APIs de multiplexação de alta capacidade específicas da plataforma. Esses reatores incluem o reator KQueue baseado no mecanismo kqueue no FreeBSD, o reator epoll no sistema que suporta a interface epoll (atualmente Linux 2.6) e o reator IOCP baseado nas portas de conclusão de entrada e saída no Windows.

Entre os detalhes relevantes da implementação da votação, a Twisted precisa considerar:

  • Limitações de rede e sistema de arquivos
  • Comportamento de buffer
  • Como detectar a perda de conexão
  • Valor de retorno quando ocorre um erro

A implementação do reator do Twisted também considera o uso correto da API sem bloqueio subjacente e lida corretamente com várias condições de contorno. Como a API IOCP não é exposta em Python, o Twisted precisa manter sua própria implementação.

Gerenciar cadeias de retorno de chamada

O retorno de chamada é a base do modelo de programação orientado a eventos e também é uma maneira do reator notificar o aplicativo de que o evento foi processado. À medida que a escala do programa continua a se expandir, os programas orientados a eventos precisam lidar com o sucesso e o erro do processamento de eventos ao mesmo tempo, o que torna o programa cada vez mais complexo. Se um retorno de chamada adequado não for registrado, o programa será bloqueado, porque o processo de tratamento de eventos nunca acontecerá. Quando ocorre um erro, a cadeia de retorno de chamada precisa ser passada da pilha da rede por meio de diferentes camadas do aplicativo.

Abaixo estão duas partes do pseudocódigo Python, que são códigos de brinquedo para obter URLs nos modos síncrono e assíncrono. Vamos comparar essas duas versões entre si para ver quais são as falhas no programa orientado a eventos:

Obtenha o URL de forma síncrona:

import getPage
 
def processPage(page):
    print page
 
def logError(error):
    print error
 
def finishProcessing(value):
    print "Shutting down..."
    exit(0)
 
url = "http://google.com"
try:
    page = getPage(url)
    processPage(page)
except Error, e:
    logError(error)
finally:
    finishProcessing()

Obtenha o URL de forma assíncrona:

from twisted.internet import reactor
import getPage
 
def processPage(page):
    print page
    finishProcessing()
 
def logError(error):
    print error
    finishProcessing()
 
def finishProcessing(value):
    print "Shutting down..."
    reactor.stop()
 
url = "http://google.com"
# getPage takes: url, 
# success callback, error callback
getPage(url, processPage, logError)
 
reactor.run()

Na versão assíncrona do buscador de URL, reactor.run () inicia o loop de eventos do reator. Na versão síncrona e assíncrona do programa, presumimos que a função getPage lida com o trabalho de obtenção da página. Se a busca for bem-sucedida, processPage é chamado. Se ocorrer uma exceção ao tentar obter a página, logError é chamado. Em qualquer um dos casos, finishProcessing deve ser chamado no final.

O retorno de chamada logError na versão assíncrona corresponde ao bloco try / except na versão síncrona. O retorno de chamada para processPage corresponde ao bloco else, e o finishProcessing do retorno de chamada incondicional corresponde ao bloco finally.

Na versão síncrona, a estrutura do código mostra diretamente que existe um bloco try / except.Apenas um entre logError e processPage será chamado uma vez, e finishProcessing sempre será chamado uma vez. Na versão assíncrona, o próprio programador é responsável por chamar corretamente a cadeia de retorno de chamada em caso de sucesso ou falha. Se finishProcessing não for chamado após a cadeia de retorno de chamada de processPage ou logError devido a um erro de programação, o loop de evento do reator nunca será interrompido e o programa ficará travado.

Este exemplo de brinquedo nos diz que essa complexidade frustrou os programadores durante os primeiros anos de desenvolvimento do Twisted. A maneira do Twisted de lidar com essa complexidade é adicionar um novo objeto chamado Deferred.

Adiado

O objeto Adiado expressa um pensamento de forma abstrata que o resultado ainda não existe. Também pode ajudar a gerenciar a cadeia de retorno de chamada necessária para produzir esse resultado. Ao retornar de uma função, o objeto Deferred promete que a função produzirá um resultado em algum ponto. O objeto Deferred retornado contém todas as referências de retorno de chamada registradas para o evento, portanto, apenas esse objeto precisa ser passado entre as funções. Rastrear esse objeto é muito mais simples do que gerenciar todos os retornos de chamada individualmente.

O objeto Deferred contém um par de cadeias de retorno de chamada, uma é o retorno de chamada para o sucesso da operação e a outra é o retorno de chamada para o fracasso da operação. No estado inicial, ambas as cadeias do objeto Adiado estão vazias. No processo de processamento de eventos, cada estágio adiciona retornos de chamada para processamento bem-sucedido e retornos de chamada para falhas de processamento. Quando um resultado assíncrono chega, o objeto Adiado é "ativado", então os retornos de chamada para processamento bem-sucedido e os retornos de chamada para falha no processamento podem ser chamados de maneira apropriada na ordem em que foram adicionados.

O código após usar o objeto Deferred na versão assíncrona do buscador de URL é o seguinte:

from twisted.internet import reactor
import getPage
 
def processPage(page):
    print page
 
def logError(error):
    print error
 
def finishProcessing(value):
    print "Shutting down..."
    reactor.stop()
 
url = "http://google.com"
deferred = getPage(url) # getPage returns a Deferred
deferred.addCallbacks(success, failure)
deferred.addBoth(stop)
 
reactor.run()

As funções de manipulação de eventos chamadas nesta versão são as mesmas de antes, mas todas são registradas em um objeto Deferred separado, em vez de serem espalhadas pelo código e passadas para getPage como parâmetros.

A criação do objeto Adiado contém dois estágios de adição de retornos de chamada. No primeiro estágio, addCallbacks adiciona processPage e logError a suas respectivas cadeias de retorno de chamada. Em seguida, addBoth adiciona finishProcessing às duas cadeias de retorno de chamada ao mesmo tempo. Olhando graficamente, a cadeia de retorno de chamada deve ser conforme mostrado na Figura 21.2:

Figura 21.2 Cadeia de retorno de chamada

O objeto Adiado só pode ser ativado uma vez, e uma exceção será gerada se ele tentar ser ativado repetidamente. Isso torna a semântica do objeto Deferred bastante próxima do bloco try / except na versão síncrona. Isso torna o processamento de eventos assíncronos mais fácil de inferir e evita bugs sutis devido a mais ou menos uma chamada de retorno para um único evento.

Entender objetos adiados é muito importante para entender o fluxo de execução de programas Twisted. No entanto, ao usar a abstração de alto nível para protocolos de rede que o Twisted nos fornece, em circunstâncias normais, não precisamos usar o objeto Deferred diretamente.

O conceito abstrato contido no objeto Deferred é muito poderoso e essa ideia foi emprestada por muitas outras plataformas orientadas a eventos, incluindo jQuery, Dojo e Mochikit.

Transportes

Os transportes representam a conexão entre dois nós de comunicação na rede. Transports é responsável por descrever os detalhes da conexão, como se a conexão é orientada a stream ou datagrama, controle de fluxo e confiabilidade. Sockets TCP, UDP e Unix podem ser usados ​​como exemplos de transportes. Eles são projetados para "satisfazer a menor unidade funcional enquanto têm o maior grau de reutilização" e são separados da implementação do protocolo, o que permite que muitos protocolos usem o mesmo tipo de transmissão. Transports implementa a interface ITransports, que contém os seguintes métodos:

write                   以非阻塞的方式按顺序依次将数据写到物理连接上
writeSequence           将一个字符串列表写到物理连接上
loseConnection          将所有挂起的数据写入,然后关闭连接
getPeer                 取得连接中对端的地址信息
getHost                 取得连接中本端的地址信息

Separar os transportes do protocolo também torna mais fácil testar esses dois níveis. Você pode simular a transmissão simplesmente escrevendo uma string e verificar desta forma.

Protocolos

Os protocolos descrevem como processar eventos na rede de maneira assíncrona. HTTP, DNS e IMAP são exemplos de protocolos da camada de aplicativo. Protocolos implementa a interface IProtocol, que contém os seguintes métodos:

makeConnection在transport对象和服务器之间建立一条连接

connectionMade连接建立起来后调用

dataReceived接收数据时调用

connectionLost关闭连接时调用

É melhor usar um exemplo para ilustrar a relação entre reator, protocolos e transportes. A seguir está a implementação do cliente e servidor de eco completos. Primeiro, vamos dar uma olhada na parte do servidor:

from twisted.internet import protocol, reactor
 
class Echo(protocol.Protocol):
    def dataReceived(self, data):
        # As soon as any data is received, write it back
        self.transport.write(data)
 
class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()
 
reactor.listenTCP(8000, EchoFactory())
reactor.run()

Depois, há a parte do cliente:

from twisted.internet import reactor, protocol
 
class EchoClient(protocol.Protocol):
    def connectionMade(self):
        self.transport.write("hello, world!")
 
def dataReceived(self, data):
    print "Server said:", data
        self.transport.loseConnection()
 
def connectionLost(self, reason):
    print "connection lost"
 
class EchoFactory(protocol.ClientFactory):
    def buildProtocol(self, addr):
        return EchoClient()
 
def clientConnectionFailed(self, connector, reason):
    print "Connection failed - goodbye!"
        reactor.stop()
 
def clientConnectionLost(self, connector, reason):
    print "Connection lost - goodbye!"
        reactor.stop()
 
reactor.connectTCP("localhost", 8000, EchoFactory())
reactor.run()

A execução do script do lado do servidor iniciará um servidor TCP, ouvindo conexões na porta 8000. O servidor usa o protocolo Echo e os dados são gravados por meio do objeto de transporte TCP. A execução do script do cliente iniciará uma conexão TCP com o servidor, ecoará a resposta do servidor e, em seguida, encerrará a conexão e interromperá o loop de eventos do reator. O Factory aqui é usado para gerar instâncias de objetos de protocolo para ambas as partes conectadas. A comunicação entre as duas pontas é assíncrona, o connectTCP é responsável por registrar a função de callback no loop de eventos do reator, e notificar o processamento de callback quando houver dados para ler no socket.

Formulários

Twisted é um mecanismo usado para criar um cliente e servidor web escalonável e multiplataforma. Em um ambiente de produção, simplificar o processo de implantação desses aplicativos de maneira padronizada é uma parte muito importante para uma plataforma amplamente adotada como a Twisted. Para isso, a Twisted desenvolveu um conjunto de componentes básicos de aplicativos para implantar aplicativos Twisted de forma reutilizável e configurável. Essa abordagem permite que os programadores evitem empilhar códigos pré-fabricados para integrar aplicativos com ferramentas existentes, incluindo daemonização, processamento de log, uso de loops de reator customizados e análise de desempenho do código.

Os componentes básicos de um aplicativo incluem 4 partes principais: Serviço, Aplicativo, Gerenciamento de Configuração (por meio de arquivos TAC e plug-ins) e programa de linha de comando twistd. Para ilustrar esse componente básico, transformaremos o servidor Echo da seção anterior em um aplicativo.

Serviço

Serviço é um componente que pode ser iniciado e interrompido implementado na interface IService. Twisted vem com TCP, FTP, HTTP, SSH, DNS e outros serviços e a implementação de outros protocolos. Muitos desses serviços podem ser registrados em um aplicativo separado. O núcleo da interface IService é:

startService启动服务。可能包含加载配置数据,设定数据库连接或者监听某个端口

stopService关闭服务。可能包含将状态保存到磁盘,关闭数据库连接或者停止监听端口

Nosso serviço Echo usa o protocolo TCP, portanto, podemos usar a implementação TCPServer padrão na interface IService no Twisted.

Inscrição

O aplicativo é o serviço de nível superior, que representa todo o aplicativo Twisted. O serviço precisa se registrar no aplicativo e, em seguida, você pode pesquisar e executar o aplicativo com a ferramenta de implantação twistd que apresentaremos a seguir. Criaremos um aplicativo Echo que pode ser registrado no Echo Service.

Arquivo TAC

Ao gerenciar o aplicativo Twisted em um arquivo Python comum, o desenvolvedor é responsável por escrever o código para iniciar e parar o loop de eventos do reator e configurar o aplicativo. Nos componentes básicos do Twisted, a implementação do protocolo é completada em um módulo. Os serviços que precisam utilizar esses protocolos podem ser registrados em um arquivo de configuração do aplicativo Twisted (arquivo TAC), de forma que o loop de eventos do reator e a configuração do programa possam ser gerenciado por componentes externos.

Para transformar nosso servidor Echo em um aplicativo Echo, podemos concluir as seguintes etapas simples:

  1. Mova a parte do protocolo do servidor Echo para seu próprio módulo.
  2. No arquivo TAC:
    1. Crie um aplicativo Echo.
    2. Crie uma instância do serviço TCPServer, ela usará nosso EchoFactory e, em seguida, concluirá o registro com o aplicativo criado anteriormente.

O código que gerencia o loop de eventos do reator será tratado pelo twistd, que discutiremos a seguir. Dessa forma, o código do aplicativo fica assim:

arquivo echo.py:

from twisted.internet import protocol, reactor
 
class Echo(protocol.Protocol):
    def dataReceived(self, data):
        self.transport.write(data)
 
class EchoFactory(protocol.Factory):
    def buildProtocol(self, addr):
        return Echo()

 

torção

twistd (pronuncia-se "twist-dee") é uma ferramenta de plataforma cruzada para implantar aplicativos Twisted. Ele executa o arquivo TAC e se encarrega de iniciar e interromper o aplicativo. Como parte da capacidade de "bateria embutida" do Twisted na programação de rede, o twistd vem com alguns sinalizadores de configuração muito úteis, incluindo transformar aplicativos em daemons, definir caminhos de arquivo de log, definir níveis de privilégio e executar em chroot. Use um reator não padrão ou até mesmo executar o aplicativo no criador de perfil.

Podemos executar este aplicativo de serviço Echo assim:

$ twistd –y echo_server.tac

Neste exemplo simples, twistd inicia o aplicativo como um daemon e o log é registrado no arquivo twistd.log. Depois de iniciar e parar o aplicativo, o conteúdo do arquivo de log é o seguinte:

2011-11-19 22:23:07-0500 [-] Logopened.

2011-11-19 22:23:07-0500 [-]twistd11.0.0 (/usr/bin/python2.7.1)startingup.

2011-11-19 22:23:07-0500 [-]reactor class:twisted.internet.selectreactor.SelectReactor.

2011-11-19 22:23:07-0500 [-]echo.EchoFactorystartingon8000

2011-11-19 22:23:07-0500 [-] Startingfactory<echo.EchoFactoryinstanceat0x12d8670>

2011-11-19 22:23:20-0500 [-] Received SIGTERM, shutting down.

2011-11-19 22:23:20-0500 [-] (TCP Port 8000 Closed)

2011-11-19 22:23:20-0500 [-] Stopping factory <echo.EchoFactory instance at 0x12d8670>

2011-11-19 22:23:20-0500 [-] Main loop terminated.

2011-11-19 22:23:20-0500 [-] Server Shut Down.

Usando os componentes básicos na estrutura Twisted para executar serviços, isso permite que os desenvolvedores não tenham mais que escrever código redundante, como daemons e registro. Isso também estabelece uma interface de linha de comando padrão para implantação de aplicativos.

Plugins

Para o método de execução do aplicativo Twisted, existe um método opcional além do arquivo TAC, que é o sistema de plug-in. O sistema TAC pode registrar facilmente os serviços predefinidos Twisted com o arquivo de configuração do aplicativo e o sistema de plug-in pode registrar facilmente o serviço definido pelo usuário como um subcomando da ferramenta twistd e, em seguida, expandir a interface de linha de comando do aplicativo.

Ao usar o sistema de plug-in:

  1. Uma vez que apenas a API do plugin precisa ser estável, isso permite que desenvolvedores terceirizados estendam o software facilmente.
  2. O recurso de descoberta do plug-in foi integrado ao sistema. O plug-in pode ser carregado e salvo quando o programa é executado pela primeira vez, e o processo de descoberta do plug-in será acionado novamente toda vez que o programa for iniciado, ou pode ser repetidamente pesquisado para novos plug-ins durante a execução do programa. O plug-in é instalado.

Ao usar o sistema de plug-ins Twisted para estender o software, basta criar os objetos implementados na interface IPlugin e colocá-los em um local específico, onde o sistema de plug-ins saiba como encontrá-los.

Convertemos o serviço Echo em um aplicativo Twisted e convertê-lo em um plugin Twisted é muito simples. Em nosso módulo Echo anterior, além da definição do protocolo Echo e EchoFactory, agora precisamos adicionar um diretório chamado twistd, que também contém um subdiretório chamado plugins, aqui está o que precisamos para definir o plug-in Echo. Por meio desse plug-in, podemos iniciar um serviço de eco e atribuir o número da porta que precisa ser usado como parâmetro para a ferramenta twistd.

from zope.interface import implements
 
from twisted.python import usage
from twisted.plugin import IPlugin
from twisted.application.service import IServiceMaker
from twisted.application import internet
 
from echo import EchoFactory
 
class Options(usage.Options):
    optParameters = [["port", "p", 8000, "The port number to listen on."]]
 
class EchoServiceMaker(object):
    implements(IServiceMaker, IPlugin)
    tapname = "echo"
    description = "A TCP-based echo server."
    options = Options
 
def makeService(self, options):
    """
    Construct a TCPServer from a factory defined in myproject.
    """
    return internet.TCPServer(int(options["port"]), EchoFactory())
 
serviceMaker = EchoServiceMaker()

Agora, nosso servidor Echo aparecerá como uma opção de serviço na saída de twistd –help. Executar twistd echo –port = 1235 iniciará um servidor Echo na porta 1235.

Twisted também vem com um módulo de autenticação do lado do servidor plugável twisted.cred O uso comum do sistema de plug-in é adicionar um modo de autenticação ao aplicativo. Podemos usar a classe AuthOptionMixin pronta em twisted.cred para adicionar suporte de linha de comando para várias autenticações ou para adicionar novos tipos de autenticação. Por exemplo, podemos usar um sistema de plug-in para adicionar um método de autenticação baseado em um banco de dados de senhas Unix local ou um servidor LDAP.

A ferramenta twistd vem com muitos plug-ins de protocolo suportados pelo Twisted e você pode iniciar o servidor com um único comando. Aqui estão alguns exemplos de como iniciar o servidor via twistd:

twistdweb–port 8080 –path .

Este comando iniciará um servidor HTTP na porta 8080, que é responsável pelo processamento de solicitações de páginas estáticas e dinâmicas no diretório atual.

twistd dns –p 5553 –hosts-file=hosts

Este comando inicia um servidor DNS na porta 5553 e resolve o nome de domínio nos hosts de arquivo especificados.O formato de conteúdo deste arquivo é o mesmo que / etc / hosts.

sudo twistd conch –ptcp:2222

Este comando inicia um servidor SSH na porta 2222. A chave ssh deve ser definida de forma independente.

twistdmail –E –H localhost –d localhost=emails

Este comando inicia um servidor ESMTP POP3, recebe e-mails para o host local e os salva no diretório de e-mails especificado.

Podemos construir facilmente um servidor para testar as funções do cliente por meio do twistd, mas também é uma implementação de servidor carregável em nível de produto.

No que diz respeito à implantação de aplicativos, o Twisted teve sucesso com a implantação de arquivos TAC, plug-ins e a ferramenta de linha de comando twistd. Mas o que é interessante é que, para a maioria dos grandes aplicativos Twisted, implantá-los ainda requer a reescrita de alguns desses componentes de gerenciamento e monitoramento; a arquitetura do Twisted não mostra muita compatibilidade com as necessidades dos administradores de sistema. Isso também reflete o fato de que Twisted nunca teve muita arquitetura para administradores de sistema, e esses administradores de sistema são especialistas em implantação e manutenção de aplicativos. Nesse sentido, o Twisted precisa solicitar mais ativamente o feedback de tais usuários especialistas na tomada de decisões de design de arquitetura futura.

21.3 Reflexões e lições

O Twisted recentemente completou 10 anos. Desde o estabelecimento do projeto, inspirado em jogos online no início dos anos 2000, o atual Twisted alcançou amplamente seu objetivo de ser um mecanismo de rede escalonável, multiplataforma e baseado em eventos. Twisted é amplamente utilizado em ambientes de produção, do Google, Lucasfilm à plataforma de colaboração de software Justin.TV e Launchpad. A implementação do lado do servidor no Twisted é o núcleo de vários softwares de código aberto, incluindo BuildBot, BitTorrent e TahoeLAFS.

Desde seu desenvolvimento inicial até o presente, a arquitetura de Twisted passou por várias mudanças importantes. Objetos adiados foram adicionados como uma parte chave. Conforme mencionado anteriormente, isso é usado para gerenciar os resultados atrasados ​​e a cadeia de retorno de chamada correspondente.

Outra parte importante foi removida e quase não há sombra na implementação atual.Isto é Twisted Application Persistence.

Persistência de aplicativo torcido

A persistência de aplicativo torcida (TAP) refere-se a salvar a configuração e o estado do aplicativo em um pickle. Para executar um aplicativo usando este esquema, são necessárias duas etapas:

Use a ferramenta mktap para criar um pickle que representa o aplicativo (esta ferramenta está obsoleta).

Use a ferramenta de linha de comando twistd para remover a seleção e, em seguida, execute o aplicativo.

Este processo é inspirado por imagens Smalltalk, porque odiamos as linguagens de configuração especiais temporárias e difíceis de usar, e não queremos que continuem a se espalhar no projeto. Preferimos expressar os detalhes da configuração em Python.

Logo, o arquivo TAP introduziu complexidade desnecessária. Modificar as classes em Twisted não altera as instâncias dessas classes em pickle. Usar a nova versão de métodos de classe ou atributos em objetos pickle pode travar todo o aplicativo. Portanto, o conceito de "versão atualizada" é introduzido, ou seja, os objetos pickle são atualizados para uma nova versão da API. Mas isso resultará em um fenômeno de matriz de versões atualizadas, e vários objetos pickle de diferentes versões aparecerão. Portanto, o teste de unidade precisa manter e cobrir todos os caminhos de atualização possíveis. Ainda é difícil e sujeito a erros rastrear todas as alterações de interface de forma abrangente.

O TAP e os componentes relacionados foram todos abolidos e, finalmente, completamente eliminados do Twisted. Substituído pelo arquivo TAC e sistema de plug-in. A sigla TAP foi redefinida como Twisted Application Plugin (Twisted Application Plugin) e agora é difícil encontrar um traço do sistema pickle no Twisted.

A lição que aprendemos com o fiasco da TAP é que, para racionalizar a manutenibilidade, é necessário que haja um modelo claro para dados persistentes. De forma mais geral, aprendemos como adicionar complexidade a um projeto: quando um novo sistema precisa ser introduzido para resolver um determinado problema, temos que entender corretamente a complexidade da solução e passá-la por testes. O valor do novo sistema deve ser significativamente maior do que sua complexidade. Depois de garantir isso, podemos colocar o plano no projeto.

web2: Lições de refatoração

Embora essa não seja basicamente uma decisão sobre o design de arquitetura, da perspectiva do gerenciamento de projetos, reescrever a implementação da Web do Twisted tem uma perspectiva de longo prazo sobre a imagem externa do Twisted e a capacidade dos mantenedores de fazer melhorias arquitetônicas em outras partes da base de código. vale a pena discutir brevemente aqui.

Em meados de 2000, os desenvolvedores do Twisted decidiram reescrever completamente a API twisted.web e implementá-la como um projeto separado na base de código Twisted, que é web2. web2 incluirá muitas melhorias e aprimoramentos para o twisted.web original, incluindo suporte completo para HTTP 1.1 e suporte de API para streaming de dados.

web2 foi inicialmente um projeto experimental, mas eventualmente foi adotado por grandes projetos e até mesmo acidentalmente empacotado e lançado no sistema Debian. O desenvolvimento de twisted.web e web2 vem acontecendo em paralelo há muitos anos. Novos usuários são frequentemente confundidos por esses dois projetos paralelos. A falta de dicas claras sobre qual implementação deve ser usada deixa os novos usuários muito frustrados. A transição para web2 nunca aconteceu e, finalmente, o desenvolvedor o removeu da base de código em 2011 e não estava mais visível na página inicial oficial. Algumas melhorias feitas no web2 também foram lentamente transferidas para o twisted.web.

Twisted adquiriu a "notoriedade" de difícil navegação e estrutura confusa, que pode facilmente confundir novos desenvolvedores. Essa impressão é parcialmente atribuída à web2. Mesmo alguns anos depois, a comunidade Twisted ainda está lutando contra essa reputação discordante.

A lição que aprendemos com o web2 é que refatorar um projeto do zero geralmente é uma má ideia. Mas se você deve fazer isso, certifique-se de que a comunidade de desenvolvedores entenda a importância disso em longo prazo e que deve haver uma escolha clara na comunidade de usuários sobre qual implementação usar.

Se o Twisted puder voltar à era da web2, os desenvolvedores devem fazer uma série de alterações compatíveis com versões anteriores em twisted.web em vez de refatorar.

Acompanhe a onda da Internet

A forma como usamos a Internet ainda está evoluindo. Em relação à implementação de vários protocolos como parte do núcleo do software, esta decisão técnica faz com que o Twisted suporte o pesado fardo de manter esses protocolos. Com as mudanças nos padrões e a adoção de novos protocolos, a implementação original deve evoluir, enquanto a compatibilidade com versões anteriores é necessária.

O Twisted é basicamente um projeto de voluntariado.O fator limitante para o desenvolvimento do projeto não é o entusiasmo da comunidade técnica, mas o tempo do voluntariado. Por exemplo, a especificação HTTP 1.1 foi definida na RFC 2616 em 1999, mas a adição do suporte HTTP 1.1 à implementação do protocolo HTTP do Twisted só começou em 2005 e já era 2009 quando foi concluída. O suporte para IPv6 foi definido no RFC 2460 em 1998, e o suporte da Twisted para ele ainda está em andamento, mas não foi incorporado até 2011.

À medida que as interfaces dos sistemas operacionais suportados mudam, a implementação também evolui. Por exemplo, o mecanismo de notificação de eventos epoll foi adicionado ao Linux versão 2.5.44 em 2002, e Twisted posteriormente desenvolveu um loop de eventos de reator baseado em epoll para utilizar esta nova interface do sistema. Em 2007, no sistema OS 10.5 Leopard lançado pela Apple, a implementação do system call poll não suportava periféricos, para a Apple esse problema bastava para bloquear a interface select.poll no próprio Python do sistema. Twisted teve que resolver esse problema por conta própria e tem fornecido documentação aos usuários desde então.

Às vezes, o desenvolvimento do Twisted não acompanhava as mudanças no mundo online e algumas melhorias eram movidas para a biblioteca fora da camada central. Por exemplo, o projeto Wokkel, que é uma coleção de melhorias para o suporte Jabber / XMPP do Twisted, tem sido um projeto independente "a ser incorporado" por vários anos, mas ainda não viu a esperança de integração. Em 2009, também tentei adicionar WebSocket ao Twisted, porque os navegadores começaram a adotar suporte para o novo protocolo. Mas o plano de desenvolvimento acabou sendo transferido para outros projetos externos, porque os desenvolvedores decidiram não incluir o novo acordo até que a IETF o alterasse de um rascunho para um padrão.

Tudo isso mostra que a proliferação de bibliotecas e add-ons é um poderoso testamento da flexibilidade e escalabilidade do Twisted. Ao adotar uma estratégia de desenvolvimento orientada a testes rigorosa, bem como padrões de documentação e codificação, isso pode ajudar o projeto a evitar a necessidade de "retrocesso". Mantenha a compatibilidade com versões anteriores enquanto mantém um grande número de protocolos e plataformas com suporte. Twisted é um projeto maduro e estável e continua a manter um status de desenvolvimento muito ativo.

A Twisted está ansiosa para se tornar o motor para você viajar pela Internet nos próximos dez anos.

Acho que você gosta

Origin blog.csdn.net/smilejiasmile/article/details/111854712
Recomendado
Clasificación