2. Objetivos
• Mío: aprender, ordenar ideas.
• Para algunos: mostrarles algo que no conocían.
• Para otros: darles una razón para estudiar Python.
• Esto no es un curso de Twisted, es apenas una introducción.
• Si ya sabés Twisted:
• No te voy a contar nada nuevo.
• Tu ayuda en la charla es bienvenida!
3. Agenda
• Aplicaciones de red
• Twisted: conceptos claves y ejemplos
• Reactor
• Deferreds
• Servidores y clientes
6. Clientes
En la arquitectura C/S el remitente de una solicitud es conocido como cliente.
• Es quien inicia solicitudes o peticiones, tienen por tanto un papel activo en la
comunicación (dispositivo maestro o amo).
• Espera y recibe las respuestas del servidor.
• Por lo general, puede conectarse a varios servidores a la vez.
• Normalmente interactúa directamente con los usuarios finales mediante una interfaz
gráfica de usuario.
7. Servidores
Al receptor de la solicitud enviada por cliente se conoce como servidor.
• Al iniciarse esperan a que lleguen las solicitudes de los clientes, desempeñan
entonces un papel pasivo en la comunicación (dispositivo esclavo).
• Tras la recepción de una solicitud, la procesan y luego envían la respuesta al
cliente.
• Por lo general, aceptan conexiones desde un gran número de clientes (en ciertos
casos el número máximo de peticiones puede estar limitado).
• No es frecuente que interactúen directamente con los usuarios finales.
8. Python
• Cuantos de aca entienden esta porción de Python?
def funcion(l, b=42):
for x in l:
if x == b:
print x
numeros = [1, 4, 42, 3, 3, 42, 99, 1]
funcion(numeros)
9. Twisted
Twisted framework para hacer aplicaciones de red, basado en enventos, escrito en
Python y con licencia MIT.
• Twisted está formado por varios sus proyectos.
10. Key concepts
• Event driven
• Sin hilos
• reactor
• No bloqueante
• Deferred
• Protocolos, transports, factories y sevicios
11. Qué es bloqueante?
1. Python stdlib networking
2. Extensiones C
3. <adivina que va aca>
16. 3) Tu código
• El viejo y querido for
def procesar(datos):
for x in datos:
hacer_algo(x)
• len(datos)?
• 10
• 1000
• 1000000
• time de hacer_algo?
17. Reactor: multi tarea cooperativa
• Es el event loop que administra las aplicaciones que están corriendo.
• Provee interfaces básicas a disntios serivicos, incluyendo comunicaciones de red,
hilos, y disparo de eventos.
• Hay muchas implementaciones de reactor, cada una modificada para dar mejor
soporte a algunas características puntuales.
while True:
stuff = wait_for_stuff(timeout)
if stuff:
check_read_and_writes()
run_timed_events()
18. Reactor: distintas implementaciones
• Un reactor implementa un conjunto de interfaces. Dependiendo del elegido y la
plataforma, puede ser que algunas no estén implementadas.
• IReactorCore: funcionalidades principales (requerido)
• IReactorFDSet: usa objetos FileDescriptor
• IReactorProcess: manejo de procesos.
• IReactorSSL: soporte para SSL networking.
• IReactorTCP: soporte para TCP networking.
• IReactorThreads: administración y uso de hilos.
• IReactorTime: calendarización.
• IReactorUDP: soporte para UDP networking.
• IReactorUNIX: soporte para sockets UNIX.
19. Deferreds
• Una promesa de un resultado
• Pieza clave de construcción de todo el framework
• No convierten mágicamente código bloqueante en código asincrónico.
• from twisted.internet.defer import Deferred
20. Deferreds (addCallback)
• "Llamame cuando tengas el resulatdo."
• El que llama a una función que devuelve un Deferred puede registrar callbacks y
errbacks.
page = urlopen('http://www.python.org.ar') # bloqueante
print page.read()
d = client.getPage('http://www.python.org.ar')
def show(page):
print page
d.addCallback(show)
21. Deferreds (addErrback)
• "Si pasa algo avisame"
• El que llama a una función que devuelve un Deferred puede registrar callbacks y
errbacks.
try:
guardar_bloqueante(unDato) # bloqueante
except Excetion, e:
print "Algo no anduvo."
d = guardar_no_bloqueante(unDato) # retorna enseguida
def handle(error):
print "Algo no anduvo."
d.addErrback(handle)
22. Deferreds (errbacks y callbacks)
• El tema con los errbacks y callbacks es que vienen de a pares.
• Cuando usamos addCallback, se agrega un errback que no hace nada.
• Cuando usamos addErrback, se agrega un callback que no hace nada.
23. Deferreds (addCallbacks)
• Tenemos algunos métodos cómodos
d.addCallbacks(show, handle)
• Pero ojo! no es equivalente a
d.addCallback(show)
d.addErrback(handle)
24. Deferreds (addCallbacks)
• Si teníamos
try:
resultado = get_data_bloqueante()
resultado = procesa_datos(resultado)
except Exception, e:
resultado = maneja_excepcion(e)
• Es equivalente a
d = get_data()
d.addCallback(procesa_datos)
d.addErrback(maneja_excepcion)
25. Deferreds (addCallbacks)
• Pero si teníamos
try:
resultado = get_data_bloqueante()
except Exception, e:
resultado = maneja_excepcion(e)
else:
resultado = procesa_datos(resultado)
• Es equivalente a
d = get_data()
d.addCallbacks(procesa_datos, maneja_excepcion)
26. Deferreds
• "Tu resultado está listo"
• El que crea el deferred es responsable de llamar al callback.
• No se pueden disparar más de una vez.
• Si un deferred ya se disparó, un addCallback ejecutará directamente el callback.
class X:
def get_data(self):
self.d = Deferred()
return self.d
def data_ready(self, data)
self.d.callback(data) # solo puede ser llamado una vez!
27. deferToThread
• Útil, sobre todo cuando estamos empezando
• Puede no ser la solución más óptima a un problema
try:
Evento(tipo='W', texto=mensaje).save()
except:
logError()
se convierte en
d = deferToThread(Evento(tipo='W', texto=mensaje).save)
d.addErrback(logError)
28. Calendarizar eventos
• Ejecutar algo X segundos en el futuro
def futuro(s):
print "Se ejecutara luego de 4.1 segundos: %s" % s
reactor.callLater(4.1, futuro, "Hola, hola.")
• Si necesitamos el resultado de la ejecución:
def mostrar(resultado):
print resultado
d = task.deferLater(reactor, 4.1, futuro, "Hola, hola.")
d.addCallback(mostrar)
29. Calendarizar eventos
• Correr cada X segundos
from twisted.internet import task
def cadaSegundo():
print "paso 1 segundo"
l = task.LoopingCall(cadaSegundo)
l.start(1.0)
• También se pueden cancelar
call_id = reactor.callLater(5, f)
call_id.cancel()
31. Escribiendo servidores
• Protocolos
• Donde implementamos el manejo y el parsing.
• twisted.internet.protocol.Protocol
• Fábricas
• Donde se guardan configuraciones persistentes.
• twisted.internet.protocol.Factory
32. Protocolos
• Manejan datos en forma asincrónica.
• Responde a los eventos, tan pronto como llegan por la red.
• dataReceived
from twisted.internet.protocol import Protocol
class Echo(Protocol):
def dataReceived(self, data):
self.transport.write(data)
33. Protocolos
• Un ejemplo respondiendo a otro evento: connectionMade
from twisted.internet.protocol import Protocol
class QOTD(Protocol):
def connectionMade(self):
self.transport.write("Al que madruga Dios lo ayuda.rn")
self.transport.loseConnection()
34. Protocolos
• Un ejemplo respondiendo a otro evento: connectionLost
class Echo(Protocol):
def connectionMade(self):
self.factory.numProtocols += 1
if self.factory.numProtocols > 100:
self.transport.write("Ya somos muchos.rn")
self.transport.loseConnection()
def connectionLost(self, reason):
self.factory.numProtocols -= 1
def dataReceived(self, data):
self.transport.write(data)
35. Protocolos basados en línea
• Basados en línea (terminan en rn o CR-LF)
• Permite un modo mixto (LineReceiver)
• o no (LineOnlyReceiver)
from twisted.protocols.basic import LineReceiver
class Answer(LineReceiver):
answers = {'Como va?': 'Bien', None : "No te entiendo"}
def lineReceived(self, line):
if self.answers.has_key(line):
self.sendLine(self.answers[line])
else:
self.sendLine(self.answers[None])
36. Fábricas
• Se puede extender Factory aunque por lo general no es necesario
• Asociamos un tipo de protocolo a una fábrica y conectamos la fábrica a la red
from twisted.internet.protocol import Factory
from twisted.internet import reactor
myFactory = Factory()
myFactory.protocol = Echo
reactor.listenTCP(8007, myFactory)
reactor.run()
37. Clientes
• Protocolos
from twisted.internet.protocol import Protocol
class Bienvenida(Protocol):
def connectionMade(self):
self.transport.write("Hola servidor, yo soy tu cliente!rn")
self.transport.loseConnection()
38. Fábrica de clientes
from twisted.internet.protocol import Protocol, ClientFactory
from sys import stdout
class EchoClientFactory(ClientFactory):
def startedConnecting(self, connector):
print 'Se inicio la conexion.'
def buildProtocol(self, addr):
return Echo()
def clientConnectionLost(self, connector, reason):
print 'Se perdio la conexion por:', reason
def clientConnectionFailed(self, connector, reason):
print 'Fallo la conexion por:', reason
• Reconecciones (ReconnectingClientFactory)
39. Qué pasa con UDP?
• Lo anterior era para TCP, SSL y sockets UNIX.
• No orientado a la conexión.
• Un socket UDP puede recibir y enviar datagramas a cualquier nodo de la red.
• Los datagramas pueden no llegar en orden, duplicarse o incluso perderse!
• No hay multiples conexiones => no necesitamos fábricas, solo un protocolo.
• Usamos el reactor para conectar el protocolo con un transport UDP
• Extendemos twisted.internet.protocol.DatagramProtocol o uno de sus
convenientes hijos.
40. Ejemplo UDP
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
class Echo(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
print "recibi %r desde %s:%d" % (data, host, port)
self.transport.write(data, (host, port))
reactor.listenUDP(9999, Echo())
reactor.run()
• ConnectedUDP
• multicast UDP
41. Qué no vimos?
• Conectarse a procesos locales
• http://twistedmatrix.com/documents/current/core/howto/process.html
• Distintos tipos de reactors y cómo elejirlos
• http://twistedmatrix.com/documents/current/core/howto/choosing-reactor.html
• Logging
• http://twistedmatrix.com/documents/current/core/howto/logging.html
• Sub frameworks
• Web
• Conch
• Cred
45. Propaganda
http://python.org.ar/pyar/CharlasAbiertas2010#Twisted
Sábado 13 de Noviembre - Charlas Abiertas de Python en La Tribu (Lambaré 873,
Capital Federal)
Twisted
Vamos a ver porque el modelo de twisted es necesario, como se programa en modo
asyncronico usando deferreds y conocer el api de red de twisted para hacer servicios.
• Disertante: Lucio Torre
• 13 a 15 horas