2010-07-21 17 views
6

Tener experiencia de 1 día en Twisted Me trate de programar el envío de mensajes en respuesta a cliente TCP:Python twisted: ¿cómo programar?

import os, sys, time 
from twisted.internet import protocol, reactor 

self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
for timeout, data in self.scenario: 
     reactor.callLater(timeout, self.sendata, data) 
     print "waited %d time, sent %s\n"%(timeout, data) 

Ahora envía mensajes, pero tengo 2 problemas:
1) "tiempo de espera" va desde " now ", y quiero contarlo después de que se completó cada tarea anterior (se envió el mensaje anterior)
2) No sé cómo cerrar la conexión después de que se hayan enviado todos los mensajes. Si coloco self.transport.loseConnection() después de callLater s, se cierra la conexión inmediatamente.

En el intento anterior no usé reactor.callLater, pero solo self.transport.write() y self.transport.write() en for loop. En este caso, todos los mensajes se enviaron juntos después de que se superaran todos los tiempos de espera ... No es algo que quisiera.
El propósito es esperar la conexión del cliente, esperar timeout1 y enviar mensaje1, esperar timeout2 y enviar mensaje2, ... etc. Después del mensaje final - conexión cercana.

Respuesta

8

Lo importante a tener en cuenta cuando se trabaja con Twisted es que nada espera nada. Cuando llame al reactor.callLater(), le está pidiendo al reactor que llame a algo más tarde, no ahora. La llamada termina de inmediato (después de la llamada ha sido programada, antes se ha ejecutado.) Por lo tanto, su estado de print es una mentira: que no espera timeout tiempo; no has esperado en absoluto.

Puede fijarlo en múltiples formas y que debe usar depende de lo que realmente quiere. Si desea que la segunda tarea para iniciar cuatro segundos después de que la primera tarea comenzó , sólo tiene que añadir el retardo (su timeout variable) de la primera tarea a la espera de la segunda tarea. Sin embargo, la primera tarea puede no comenzar exactamente cuando la programes; puede comenzar más tarde, si Twisted está demasiado ocupado como para iniciarlo antes. Además, si su tarea lleva mucho tiempo, puede que no se realice antes de que comience la segunda tarea.

La forma más común es la primera tarea de programar la segunda tarea, en lugar de la programación de la segunda tarea de inmediato. Usted puede programar cuatro segundos después de que la primera tarea terminó (llamando reactor.callLater() al final de la primera tarea), o cuatro segundos después de que la primera tarea se inició (llamando reactor.callLater() al inicio de la primera tarea), o llevar a cabo más cálculos complejos para determinar cuándo debería comenzar, haciendo un seguimiento del tiempo transcurrido.

Cuando no se da cuenta de nada en Esperas retorcidas, es fácil cerrar la conexión cuando ha realizado todas las tareas programadas: simplemente tiene su última llamada al self.transport.loseConnection(). Para situaciones más complejas es posible que desee cadena Deferred es juntos, o utilizar un DeferredList para realizar la loseConnection() cuando todas las tareas pendientes han terminado, incluso cuando no son estrictamente secuencial.

+0

Gracias, ahora entiendo por qué "duerme" no funcionó. ¿Puedes dar un ejemplo con la programación de reactor.callLater() al final del reactor.callLater() anterior? – DominiCane

+0

Simplemente defina una función que llame 'self.sendata (data)' y luego llame 'reactor.callLater()' para la próxima devolución de llamada, y pase esa función al primer 'reactor.callLater()' en vez de 'self.sendata ' –

4

solución final para este acuerdo ..

import os, sys, time 
from twisted.internet import protocol, reactor 
import itertools 

def sendScenario(self): 
    def sendelayed(d): 
     self.sendata(d) 
     self.factory.out_dump.write(d) 
     try: 
      timeout, data = next(self.sc) 
      reactor.callLater(timeout, sendelayed, data) 
     except StopIteration: 
      print "Scenario completed!" 
      self.transport.loseConnection() 

    self.scenario = [(1, "Message after 1 sec!"), (4, "This after 4 secs"), (2, "End final after 2 secs")] 
    self.sc = iter(self.scenario) 
    timeout, data = next(self.sc) 
    reactor.callLater(timeout, sendelayed, data) 
+0

Solo fyi:' self.scenario .__ iter __() '->' iter (self.scenario) ',' self.sc.next() '->' next (self.sc) '(desde 2.6 creo) –

+0

Gracias, lo cambié. – DominiCane

Cuestiones relacionadas