2009-12-30 8 views
6

Quiero usar twisted (y StarPy, que es una implementación de protocolo para asterisk ami) para conectarme a un servidor de asterisco. La aplicación inicia un fax saliente allí. Encontré algunas pistas sobre mi problema, pero no puedo encontrar la forma de manejarlo correctamente.Conectar dos veces con retorcido: ¿cómo hacerlo correctamente?

El primer fax se envía correctamente.

El problema es que si llamo trenzado para la segunda vez, la aplicación mantiene colgando en el bucle principal.

Yo sé que no puedo hacer esto como aquí:

from starpy import manager 
from twisted.internet import reactor 

def main(): 
    f = manager.AMIFactory(cUser, cPass) 
    print "Login" 
    df = f.login(cServer, cPort) 

    def onLogin(protocol): 
     print "Logoff again" 
     df = protocol.logoff() 

     def onLogoff(result): 
      print "Logoff erfolgt" 
      reactor.stop() 

     return df.addCallbacks(onLogoff, onLogoff) 

    def onFailure(reason): 
     print "Login failed" 
     print reason.getTraceback() 

    df.addCallbacks(onLogin, onFailure) 
    return df 

if __name__ == "__main__": 
    reactor.callWhenRunning(main) 
    reactor.run(installSignalHandlers=0) 
    print "runned the first time" 

    reactor.callWhenRunning(main) 
    reactor.run(installSignalHandlers=0) 
    print "will never reach this point" 

que simplifica el código - no hace nada despues entrar + cierre de sesión de nuevo. Nunca regresará de la segunda llamada a reactor.run().

¿Cómo se hace esto correctamente? Estoy atrapado aquí, gracias de antemano.

Saludos cordiales, Florian.

Respuesta

3

Gracias por sus respuestas, no han implementado una solución en este momento, pero sé cómo podría hacerlo ahora ...

Aquí un breve resumen de las cosas que he aprendido.

En primer lugar, en una palabra - los problemas que tuve con twisted:

  1. Yo no entendía lo básico asíncronas de trenzado. Usé algo así en gui-frameworks pero no vi el beneficio durante mucho tiempo.
  2. En segundo lugar, traté de pensar en una llamada síncrona del ciclo de eventos varias veces. Esto era necesario en mi mente porque no puedo usar más de una línea de fax saliente a la vez. Debido a que el ciclo de eventos de retorcido no se puede reiniciar, esta no es una opción. Como pude leer en los documentos "deferToThread" podría ayudarme aquí, pero creo que no es la mejor solución.

En mi concepto que resuelven estos problemas:

Necesitaba mucha reflexión pero tan pronto como la obtienes parece muy fácil.

Gracias a iny y Jean-Paul Calderone por su ayuda.

3

No se puede reiniciar el reactor. En otras palabras, puede llamar a reactor.run() solo una vez.

En su lugar puede hacer todo lo que necesita en una ejecución del reactor.

+0

Sí, eso es lo que encontré en la web también. Pero no soy capaz de entender cómo debo manejar esto. Tal vez podría indicarme la dirección correcta: * ¿Cuándo comienzo el reactor? ¿En el inicio de la aplicación o cuando la uso por primera vez? * ¿Cómo puedo pedirle a un reactor que 1. conecte/2. enviar un fax/3. perder la conexión más de una vez? Estoy atascado. Invertí horas desarrollando y leyendo manuales. Simplemente no encuentro respuestas ... Gracias de antemano. –

+0

Lo siento, mis alimentadores de línea no funcionaron aquí. –

9

Como dijo iny, necesita hacer todo con solo una llamada a reactor.run y reactor.stop.

Si tenemos en cuenta el código de ejemplo informados, vemos que se necesita estos pasos:

  1. iniciar el reactor
    • Connect, enviar un fax, desconecte
    • parada del reactor
    • Iniciar el reactor
    • Conectar, enviar un fax, desconectar
    • Stop th e reactor

Si sólo borrar los pasos 3 y 4, entonces el programa en realidad estar haciendo una cosa bastante razonable.

Así es como ha implementado el paso 3:

def onLogoff(result): 
    print "Logoff erfolgt" 
    reactor.stop() 

Esto hizo que la primera llamada a reactor.run para regresar, despejando el camino para su realización de la etapa 4:

reactor.callWhenRunning(main) 
reactor.run(installSignalHandlers=0) 

Por lo tanto, la idea general aquí va a saltar directamente al paso 5 en lugar de hacer los pasos 3 y 4. Considere lo que podría suceder si redefine onLogoff de la siguiente manera:

def onLogoff(result): 
    print "Logoff erfolgt" 
    main() 

y eliminando las últimas tres líneas de su ejemplo.Esto realmente le dará un ciclo infinito, ya que el mismo onLogoff se ejecuta después de la segunda desconexión y comienza una tercera conexión. Sin embargo, puede remediar esto con un parámetro para la función main para controlar el comportamiento de reinicio.

Una vez que esto tenga sentido, es posible que desee pensar en mover el reintento fuera de la función main y en una devolución de llamada definida en el bloque __main__. Esta es una gran parte del poder de Deferreds: le permite mantener una separación adecuada entre la implementación de un origen de evento (en este caso, la función de envío de fax) y el código para tratar los eventos resultantes (envío de un segundo fax, o saliendo, en este caso).

+0

Ok, me das una idea. Tengo que volver a trabajar en la documentación de Deferreds. Quizás esto me impida golpear mi cabeza contra la pared. ¿Hay alguna forma de cerrar la conexión TCP saliente sin detener el reactor? No me gusta la idea de tener una sesión TCP abierta todo el tiempo ... Gracias. –

0

Si aún está buscando una solución ... tuve este problema. Tengo un script que usa Twisted para ejecutar un programa en un servidor remoto. Necesitaba una forma de ejecutar ese script de forma síncrona desde una aplicación django. Lo que terminé haciendo fue hacer que mi script Twisted llamara al servidor remoto y simplemente imprimiera en stdout. Luego, desde mi aplicación Django, ejecuté ese script a través de un subproceso. Popen y establecí stdout = PIPE para poder capturar el resultado de mi script Twisted y usarlo en mi aplicación Django.

Esto no es realmente ideal, y más bien derrota el propósito de Twisted, pero esto pasa el "no poder llamar a reactor.run() por segunda vez, ya que el script Twisted se ejecuta en su propio proceso cada uno tiempo

Esto terminó funcionando muy bien para mí, y suena muy similar a la situación en la que se encuentra. Espero que esto ayude. Buena suerte. (Puedo publicar algunos ejemplos de código si crees que lo haría ayuda, solo házmelo saber).

+0

Gracias, no me gusta este. Lo único que no me gusta de retorcido es que (en mi configuración) mantiene la conexión abierta antes de cerrarla y esperar hasta que se vuelva a necesitar. No entiendo por qué este diseño hace sentido. La asincronía sí lo hace, incluso si necesito algo de tiempo para entender. Gracias de todos modos. –

+0

Es por eso que estoy usando un subproceso, cuando el subproceso existe, la conexión se cierra. Cuando vuelvo a llamar a mi subproceso, lo abre y se cierra cuando termina. –

+1

Siempre puede llamar a 'transport.loseConnection()' si desea soltar una conexión en Twisted. ¡La razón por la que Twisted deja abierta la conexión es que no solicitó que se cerrara! – Glyph