O documento apresenta o framework Twisted para desenvolvimento de aplicações distribuídas em Python. O Twisted permite programação assíncrona, dirigida a eventos e baseada em callbacks, facilitando a criação de protocolos e servidores. Apresenta conceitos-chave como reactor, assincronismo, callbacks, protocolos, fábricas e casos de uso do Twisted.
Twisted Framework: desenvolver aplicações distribuídas nunca foi tão fácil
1. Twisted Framework
Desenvolver aplica¸˜es distribu´
co ıdas nunca foi t˜o f´cil
a a
Pedro Arthur P. R. Duarte (JEdi)
Msc. student in Computer Networks Management – UFRGS
Core Developer – HLBR Project
2. O Mote de nossa Palestra
Instanciar ou Sobrecarregar?
Introdu¸˜o
ca
Twisted, djab´isso?
e Que venham os clientes!
Building Blocks Programa¸˜o Ass´
ca ıncrona
Assincronismo, Eventos e Chamadas n˜o bloqueantes
a
Callbacks Deferreds
O La¸o de eventos
c Callbacking
Ol´, mundo!
a Errbacking
A f´rmula m´gica dos
o a
Protocolos e F´bricas
a
Deferreds
Criando protocolos
The Useless Protocol!
E quem usa o Twisted?
F´bricas, pra que te quero?
a Alguns casos de sucesso
Instanciando F´bricas
a Aos Finalmentes
Sobrecarregando f´bricas
a Perguntas e Contatos
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
3. Twisted, djab´isso?
e
Framework Python para aplica¸˜es distribu´
co ıdas:
Esque¸a os detalhes de baixo n´
c ıvel!
Mas use-os se quiser :-)
Bin´rios dispon´
a ıveis nos melhores gerenciadores de pacotes;
E os fontes em http://twistedmatrix.com;
Orienta¸˜o ` objetos e Padr˜es de Projeto levados a s´rio!
ca a o e
Protocolos prontos para usar!
HTTP, FTP, SSH, SMTP/IMAP, SSL, DNS, Netstring,
SNMP, XMPP, dentre outros...
Basta adicionar ´gua :-)
a
Ass´
ıncrono, dirigido ` eventos e baseado em callbacks;
a
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
4. Assincronismo, eventos, callbacks? Cuma?
N˜o nos chame. Pode deixar que n´s chamamos vocˆ!
a o e
– Reversal Tw´
ıstica
Para o Twisted, existem apenas eventos!
Novas conex˜es, dados recebidos, conex˜es fechadas, erros de
o o
transmiss˜o, etc, etc, etc;
a
Callbacks tratam os eventos!
connectionMade, dataReceived, connectionLost,
connectionRefused, etc, etc, etc;
E quando os eventos ocorrem?
N˜o se sabe... S˜o completamente ass´
a a ıncronos... /o
Por´m, seguem regras bem definidas! o/
e
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
5. Contemplem, o la¸o de eventos!
c
Cuida dos detalhes de I/O do sistema operacional,
networking, temporizadores, threading, ...
Na verdade, s´ n˜o faz chover!
o a
Padr˜o Reactor
a
A concurrent programming pattern for handling service requests delivered
concurrently to a service handler by one or more inputs. The service handler
then demultiplexes the incoming requests and dispatches them synchronously
to the associated request handlers.
S´ pode haver um!
o
– Highlander, 1 . . . n
Separa¸˜o entre c´digo de aplica¸˜o e do reator:
ca o ca
O reator n˜o tem no¸˜o sobre a aplica¸˜o;
a ca ca
As aplica¸˜es s´ conhecem as interfaces do reator;
co o
Reuso e Modularidade;
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
6. Ol´ mundo, num modo Twisted de ser!
a
1 from t w i s t e d . i n t e r n e t import r e a c t o r
3 def helloWorld ( ) :
4 p r i n t ” H e l l o World ! ”
6 r e a c t o r . callWhenRunning ( helloWorld )
7 r e a c t o r . callWhenRunning ( r e a c t o r . stop )
9 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
7. O nascimento de um novo protocolo
Protocolos s˜o componentes independentes;
a
N˜o est˜o diretamente associados ` protocolos de rede,
a a a
transporte ou qualquer outra coisa;
N˜o conhecem portas, nem endere¸os, nem nada!
a c
Implementa¸˜es de twisted.internet.protocol.Protocol
co
connectionMade(self)
dataReceived(self, data)
connectionLost(self, reason)
ou filhas de pais ricos:
twisted.protocols.basic.LineReceiver
twisted.protocols.basic.NetstringReceiver
twisted.protocols.ftp.FTP
twisted.web.http.HTTPChannel
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
8. O protocolo mais in´til do mundo
u
1 from t w i s t e d . i n t e r n e t . p r o t o c o l import P r o t o c o l
3 class UselessProtocol ( Protocol ):
4 def init ( self ):
5 ’ ’ ’My i n s t a n t i a t i o n p h a s e ’ ’ ’
6 pass
8 def connectionMade ( s e l f ) :
9 ’ ’ ’ Someone c o n n e c t e d . Here g o e s i t ’ s QOTD ’ ’ ’
10 s e l f . t r a n s p o r t . w r i t e ( ”Welcome , d e a r u s e r ! n” )
12 def dataReceived ( s e l f , data ) :
13 ’ ’ ’ U s e r s e n d s me d a t a ! We ’ l l e c h o e s i t back ’ ’ ’
14 s e l f . t r a n s p o r t . w r i t e ( data )
16 def c o n n e c t i o n L o s t ( s e l f , reason ) :
17 ’ ’ ’ And , i t s gonne . . . ’ ’ ’
18 print reason
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
9. Fabricando servidores
Together we stand, divided we fall!
– Hey you, Pink Floyd
Sozinhos, protocolos n˜o s˜o nada!
a a
Eles precisam de f´bricas:
a
twisted.internet.protocol.Factory
Padr˜o Factory
a
Define an interface for creating an object, but let the subclasses decide which
class to instantiate. The Factory method lets a class defer instantiation to
subclasses.
E tamb´m precisam da aten¸˜o do la¸o de eventos!
e ca c
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
10. Revisitando nosso in´til protocolo
u
Abordagem 1: Instanciando uma Factory
1 from t w i s t e d . i n t e r n e t . p r o t o c o l import P r o t o c o l , F a c t o r y
2 from t w i s t e d . i n t e r n e t import r e a c t o r
4 class UselessProtocol ( Protocol ):
5 ’ ’ ’ E v e r y t h i n g we ’ v e done b e f o r e ’ ’ ’
7 factory = Factory ()
8 factory . protocol = UselessProtocol
10 r e a c t o r . listenTCP (10101 , f a c t o r y )
11 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
11. Nosso in´til protocolo revisitado
u
Abordagem 2: Sobrecarregando uma Factory
1 from t w i s t e d . i n t e r n e t . p r o t o c o l import P r o t o c o l , F a c t o r y
2 from t w i s t e d . i n t e r n e t import r e a c t o r
4 class UselessProtocol ( Protocol ):
5 ’ ’ ’ E v e r y t h i n g we ’ v e done b e f o r e ’ ’ ’
7 class UselessFactory ( Factory ) :
8 protocol = UselessProtocol
10 r e a c t o r . listenTCP (10101 , U s e l e s s F a c t o r y ( ) )
11 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
12. Instanciar ou Sobrecarregar? Eis a quest˜o
a
Quando...
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
13. Instanciar ou Sobrecarregar? Eis a quest˜o
a
Quando...
Instanciar
N˜o h´ necessidade de persistir
a a
ou compartilhar dados entre os
diversos clientes
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
14. Instanciar ou Sobrecarregar? Eis a quest˜o
a
Quando...
Instanciar Sobrecarregar
N˜o h´ necessidade de persistir
a a H´ a necessidade de persistir ou
a
ou compartilhar dados entre os compartilhar dados entre os
diversos clientes diversos clientes
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
15. Sem conversa mole! Queremos c´digo!
o
Uma micro Honeypot
1 from t w i s t e d . i n t e r n e t . p r o t o c o l import P r o t o c o l , F a c t o r y
2 from t w i s t e d . i n t e r n e t import r e a c t o r
4 c l a s s GenericHoneyPot ( Protocol ) :
5 def connectionMade ( s e l f ) :
6 peer = s e l f . t r a n s p o r t . getHost ()
7 p r i n t ’ {0} h a s c o n n e c t e d t o {1} ( { 2 } ) ’ . f o r m a t (
8 peer . host , s e l f . f a c t o r y . l s t P r t , peer . type )
9 i f s e l f . f a c t o r y . cmData i s not None :
10 s e l f . t r a n s p o r t . w r i t e ( s e l f . f a c t o r y . cmData )
12 def dataReceived ( s e l f , data ) :
13 i f s e l f . f a c t o r y . d r D a t a i s not None :
14 s e l f . t r a n s p o r t . w r i t e ( s e l f . f a c t o r y . drData )
15 s e l f . transport . loseConnection ()
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
16. Sem conversa mole! Queremos c´digo!
o
Continuando nossa micro Honeypot
16 c l a s s HPFactory ( F a c t o r y ) :
17 p r o t o c o l = GenericHoneyPot
18 def init ( self , protocolData ) :
19 s e l f . l s t P r t = protocolData [ 0 ]
20 s e l f . cmData = p r o t o c o l D a t a [ 1 ]
21 s e l f . drData = p r o t o c o l D a t a [ 2 ]
23 protocols = [
24 ( 2 2 , ”SSH−2.0−OpenSSH 5 . 5 p1 Debian −4n” , ’ x01 x08 ’ ) ,
25 ( 8 0 , None , ’HTTP/ 1 . 1 404 Not Found n ’ +
26 ’ Content −L e n g t h : 0 nn ’ ) ,
27 ]
29 for p in protocols :
30 r e a c t o r . l i s t e n T C P ( p [ 0 ] , HPFactory ( p ) )
31 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
17. E clientes, eles existem no Twisted?
Existem, claro... E continuam como implementa¸˜es de
co
twisted.internet.protocol.Protocol;
Por´m, n˜o precisam de f´bricas, caso n˜o haja persistˆncia
e a a a e
entre as diversas instancia¸˜es (caso comum);
co
twisted.internet.protocol.ClientCreator
Quando precisam de f´bricas, a classe a ser sobrecarregada ´
a e
twisted.internet.protocol.ClientFactory
startedConnecting
clientConnectionLost
clientConnectionFailed
Luke, I am your father!
– Darth Vader (misquoted)
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
18. C´digos, c´digos, e mais c´digos!
o o o
Um inocente scanner de rede
1 class ScannerClient ( Protocol ):
2 def init ( self , port ) :
3 s e l f . tPort = port
5 def connectionMade ( s e l f ) :
6 p r i n t ” P o r t {0} i s open ” . f o r m a t ( s e l f . t P o r t )
7 s e l f . transport . loseConnection ()
9 def showAsClosed ( reason , tPort ) :
10 p r i n t ” P o r t {0} i s c l o s e d ” . f o r m a t ( t P o r t )
12 f o r p i n [ 2 1 , 2 2 , 2 3 , 2 5 , 8 0 , 1 1 0 , 443 ] :
13 c = ClientCreator ( reactor , ScannerClient , p)
14 d = c . connectTCP ( ”www . e x e m p l o . com” , p )
15 d . a d d E r r b a c k ( showAsClosed , p )
17 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
19. Assincronismo e Sistemas Distribu´
ıdos
Conex˜es tratadas por processo paralelos;
o
Diferentes instˆncias de um mesmo software tratam as
a
diferentes conex˜es;
o
O sistema operacional encarrega-se do escalonamento;
Conex˜es tratadas por fluxos de execu¸˜o paralelos (threads);
o ca
Diferentes fluxo de execu¸˜o de um mesmo processo tratam as
ca
diferentes conex˜es;
o
O framework de desenvolvimento encarrega-se do
escalonamento;
Chamadas n˜o bloqueantes;
a
Um unico fluxo de execu¸˜o trata todas as conex˜es atrav´s de
´ ca o e
fun¸˜es que n˜o atrapalham a execu¸˜o do processo;
co a ca
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
20. N˜o devemos bloquear!
a
Os m´todos (callbacks) dos protocolos n˜o devem bloquear o
e a
fluxo de execu¸˜o enquanto aguardam por dados;
ca
Consultas SQL em SGBDs, leituras em descritores de arquivos,
autentica¸˜o em servidores de diret´rios, etc.
ca o
Os m´todos (callbacks) dos protocolos devem ser t˜o simples
e a
quanto poss´
ıvel. Complexidade ´ feia e nociva!
e
M´quinas de estado s˜o mais que bem vindas!
a a
La¸os O(nk ), onde k ≥ 2, nem pensar! (vide pr´ximo item)
c o
M´todos inerentemente complexos ou computacionalmente
e
intensivos tamb´m n˜o devem bloquear.
e a
E fica a pergunta: mas como?
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
21. A resposta: deferreds!
Eu vou executar, mas n˜o vou retornar agora!
a
– Deferreds da Silva
Deferreds s˜o a promessa de algum m´todo ou fun¸˜o
a e ca
retornar´ dados, mas n˜o bloquear˜o enquanto os provisiona;
a a a
Sem garantir quando esses dados estar˜o dispon´
a ıvel;
Executam callbacks quando os dados est˜o dispon´
a ıveis ou
errbacks quando algum erro ocorre.
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
22. Deferring, ou postergando resultados
Instˆncias ou sobrecargas de t.i.defer.Deferred
a
addCallback
addErrback
addCallbacks
addBoth
Quando sobrecarregar?
Quando algum motivo obscuro obrigar-lhe a alterar o
comportamento dos m´todos do Deferred; ou
e
Por elegˆncia, talvez;
a
Ou seja, quase nunca...
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
23. Instanciando Deferreds
Deferred, ´tima maneira de complicar um simples Hello World!
o
1 from t w i s t e d . i n t e r n e t . d e f e r import D e f e r r e d
2 from t w i s t e d . i n t e r n e t import r e a c t o r
4 def h e l l o D e f e r r e d ( ) :
5 d = Deferred ()
6 r e a c t o r . c a l l W h e n R u n n i n g ( d . c a l l b a c k , ” Hi , t h e r e ! ” )
7 return d
9 def p r i n t I t ( r e s u l t ) :
10 print result
11 reactor . stop ()
13 d = helloDeferred ()
14 d . addCallback ( p r i n t I t )
16 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
24. Sobrecarregando Deferreds
Crian¸as, pela gloria de Dad´, n˜o fa¸am isso em casa!
c a a c
1 from t w i s t e d . i n t e r n e t . d e f e r import D e f e r r e d
2 from t w i s t e d . i n t e r n e t import r e a c t o r
4 class HelloDefer ( Deferred ):
5 def init ( self ):
6 Deferred . init ( self )
8 def addCallback ( s e l f , c a l l b a c k ) :
9 Deferred . addCallback ( s e l f , callback )
10 r e a c t o r . c a l l W h e n R u n n i n g ( s e l f . c a l l b a c k , ” Hi ! ” )
12 def p r i n t I t ( r e s u l t ) :
13 print result
14 reactor . stop ()
16 HelloDefer ( ) . addCallback ( p r i n t I t )
17 r e a c t o r . run ( )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
25. Errbacking, ou sinalizando erros
Terminando de entender nossa Honeypot
9 def showAsClosed ( reason , tPort ) :
10 p r i n t ” P o r t {0} i s c l o s e d ” . f o r m a t ( t P o r t )
12 f o r p i n [ 2 1 , 2 2 , 2 3 , 2 5 , 8 0 , 1 1 0 , 443 ] :
13 c = ClientCreator ( reactor , ScannerClient , p)
14 d = c . connectTCP ( ”www . e x e m p l o . com” , p )
15 d . a d d E r r b a c k ( showAsClosed , p )
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
26. Deferreds, f´rmula m´gica
o a
Como postegar o resultado de qualquer chamada!
1 def BlockingFunction ( d ) :
2 r = doTheJob ( )
3 d. callback ( r )
5 def D e f e r r e d F u n c t i o n ( ) :
6 d = Deferred ()
7 r e a c t o r . callFromThread ( BlockingFunction , d)
8 return d
10 # Then , c a l l i t w h i t h o u t g e t t i n g b l o c k e d o /
11 DeferredFunction ( ) . addCallback ( myCallback )
ps: essa ´ uma solu¸˜o n00b; use t.i.threads.deferToThread
e ca
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
27. N˜o ´ apenas outro framework
a e
Esse slide tinha por objetivo apresentar casos de sucesso do
Twisted. Ele foi removido devido ao copyright das marcas
apresentadas. As informa¸˜es aqui dispon´
co ıveis podem ser
encontradas em
http://twistedmatrix.com/trac/wiki/SuccessStories
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
28. Onde consigo ajuda?
http://twistedmatrix.com/documents
Lista de discuss˜o
a
Wiki
Twisted Networking Programming Essentials (Livro)
Por Abe Fettig, O’Reilly
Network programming for the rest of us (Artigo)
Por Lefkowitz & Shtull-Trauring, USENIX 2003
Twisted Introduction
Por Deve Peticolas, http://krondo.com/
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN
29. That’s all folks...
Cr´
ıticas ou Questionamentos?
E-Mail: pedroarthur.jedi@gmail.com
paprduarte@inf.ufrgs.br
Identi.ca: @PEdrArthur
→ Tamb´m no Twitter
e
Web: http://pedroarthur.com.br (off-line)
http://blog.pedroarthur.com.br (off-line)
Pedro Arthur P. R. Duarte (JEdi) Twisted Framework 5 de Novembro de 2010, Natal/RN