витая: поймать клавиатурное прерывание и выключение должным образом - PullRequest
17 голосов
/ 11 августа 2010

ОБНОВЛЕНИЕ: Для простоты чтения, вот как добавить обратный вызов до остановки реактора:

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

Далее следует оригинальный вопрос.


Если у меня есть клиентподключен к серверу, и он охлаждается в главном контуре реактора, ожидая событий, когда я нажимаю CTRL-C, я получаю «Соединение с другой стороной было потеряно не чистым способом: соединение потеряно».Как я могу настроить его так, чтобы я знал, когда происходит KeyboardInterrupt, чтобы я мог правильно выполнять очистку и отключаться?Или как я могу реализовать более чистый способ выключения, который не включает CTRL-C, если это возможно?

Ответы [ 2 ]

30 голосов
/ 11 августа 2010

Если вы действительно, действительно хотите специально перехватить Cc, то вы можете сделать это обычным способом для приложения Python - используйте signal.signal, чтобы установить обработчик для SIGINT, который делает все, что вы хотите.Если вы вызываете любые API-интерфейсы Twisted из обработчика, убедитесь, что вы используете reactor.callFromThread, поскольку почти все другие API-интерфейсы Twisted небезопасны для вызова из обработчиков сигналов.

Однако, если вы действительно просто заинтересованы в вставке некоторых отключенийвремя очистки кода, тогда вы, вероятно, захотите использовать IService.stopService (или механизм, с помощью которого он реализован, reactor.addSystemEventTrigger).

Если вы используете twistd, тогда используйте IService.stopService легко.У вас уже есть объект Application, к которому прикреплен хотя бы один сервис.Вы можете добавить еще один с помощью пользовательского метода stopService, который выполняет работу выключения.Метод может вернуть Deferred.Если это так, то процесс выключения приостанавливается до тех пор, пока не сработает Deferred.Это позволяет вам аккуратно очистить ваши соединения, даже если для этого требуются дополнительные сетевые (или любые другие асинхронные) операции.

Если вы не используете twistd, то использование reactor.addSystemEventTrigger напрямую, вероятно, будет проще.Вы можете установить перед выключением триггер, который будет вызван в том же случае, если бы IService.stopService был вызван.Этот триггер (просто любой вызываемый объект) также может возвращать Deferred для задержки выключения.Это делается с помощью вызова reactor.addSystemEventTrigger('before', 'shutdown', callable) (когда-то до начала выключения, так что оно уже зарегистрировано, когда происходит выключение).

service.tac дает пример создания и использованияпользовательский сервис.

wxacceptance.py дает пример использования addSystemEventTrigger и задержки отключения (произвольно) на три секунды.

Оба эти механизма дадутвы уведомляете всякий раз, когда реактор останавливается.Это может произойти из-за нажатия клавиши Cc, или это может быть, потому что кто-то использовал kill -INT ..., или это может быть потому, что где-то reactor.stop() был вызван.Все они приводят к остановке реактора, и остановка реактора всегда обрабатывает триггеры событий останова.

1 голос
/ 11 августа 2010

Я не уверен, говорите ли вы о клиенте или сервере, который вы написали.

В любом случае, нет ничего плохого в 'CTRL-C'.

Если вынаписание сервера в качестве приложения.Подкласс от twisted.application.service.Service и определения startService и stopService.Вести список активных экземпляров протокола.Используйте stopService, чтобы пройти через них и изящно закрыть их.

Если у вас есть клиент, вы могли бы также создать подкласс Service, но было бы проще использовать reactor.addSystemEventTrigger('before','shutdown',myCleanUpFunction) и закрыть соединение (s) изящно в этой функции.

...