torcido: atrapa el teclado, interrumpe y apaga correctamente

ACTUALIZACIÓN: para facilitar la lectura, aquí es cómo agregar una callback antes de que el reactor se apague:

reactor.addSystemEventTrigger('before', 'shutdown', callable) 

La pregunta original sigue.


Si tengo un cliente conectado a un servidor y se está enfriando en el circuito principal del reactor esperando eventos, cuando presiono CTRL-C, aparece un mensaje “La conexión con el otro lado se perdió de forma no limpia: la conexión se perdió. ” ¿Cómo puedo configurarlo para saber cuándo ocurre una Interrupción de Teclado, para poder realizar una limpieza adecuada y desconectarme limpiamente? O, ¿cómo puedo implementar una forma más limpia de cierre que no implique CTRL-C, si es posible?

Si realmente desea capturar Cc específicamente, entonces puede hacer esto de la manera habitual para una aplicación Python: use signal.signal para instalar un controlador para SIGINT que haga lo que quiera hacer. Si invoca alguna API torcida desde el controlador, asegúrese de usar reactor.callFromThread ya que casi todas las otras API torcidas no son seguras para la invocación de los controladores de señal.

Sin embargo, si realmente está interesado en insertar algún código de limpieza en tiempo de apagado, entonces probablemente quiera usar IService.stopService (o el mecanismo en el cual se implementa, reactor.addSystemEventTrigger ).

Si está usando twistd , entonces usar IService.stopService es fácil. Ya tienes un objeto de Application con al menos un servicio adjunto. Puede agregar otro con un método de servicio de stopService personalizado que haga su trabajo de apagado. El método tiene permitido devolver un Deferred . Si lo hace, entonces el proceso de apagado se detiene hasta que se dispare el Deferred . Esto le permite limpiar bien sus conexiones, incluso si eso implica más operaciones de red (o cualquier otra asincrónica).

Si no está usando twistd , entonces usar reactor.addSystemEventTrigger directamente es probablemente más fácil. Puede instalar un desencadenador de apagado anterior que se llamará en el mismo caso en que se haya llamado a IService.stopService . Este disparador (cualquier objeto que se pueda llamar) también puede devolver un Deferred para retrasar el apagado. Esto se hace con una llamada a reactor.addSystemEventTrigger('before', 'shutdown', callable) (en algún momento antes de que se inicie el cierre, de modo que ya esté registrado cada vez que se produzca el cierre).

service.tac da un ejemplo de cómo crear y usar un servicio personalizado.

wxacceptance.py da un ejemplo de uso de addSystemEventTrigger y demora el apagado por (un arbitrario) tres segundos.

Ambos de estos mecanismos le darán una notificación cada vez que el reactor se detenga. Esto puede deberse a una pulsación de tecla Cc, o puede deberse a que alguien usó kill -INT ... , o puede deberse a que se llamó a reactor.stop() . Todos llevan al apagado del reactor, y el apagado del reactor siempre procesa los disparadores de eventos de apagado.

No estoy seguro de si está hablando de un cliente o un servidor que ha escrito.

De todos modos, no hay nada malo con ‘CTRL-C’.

Si estás escribiendo un servidor como una aplicación. Subclase de twisted.application.service.Service y defina startService y stopService . Mantener una lista de instancias de protocolo activo. Use stopService para stopService y cerrarlos con gracia.

Si tiene un cliente, también podría hacer una subclase de Service , pero podría ser más sencillo usar reactor.addSystemEventTrigger('before','shutdown',myCleanUpFunction) y cerrar las conexiones con gracia en esta función.