Скрученный: улавливать клавиатуру и прерывать работу

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

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

Исходный вопрос следует.


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

Ответы

Ответ 1

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

Однако, если вы действительно заинтересованы в вставке некоторого кода очистки после выключения, то вы, вероятно, захотите использовать 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 и задержки выключения на (произвольное) три секунды.

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

Ответ 2

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

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

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

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