扭曲:捕获KeyboardInterrupt并正确关闭

18

更新:为了更易读,以下是如何在反应器关闭之前添加回调的方法:

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

以下是原始问题。


如果我有一个连接到服务器的客户端,并且它正在反应堆主循环中等待事件,当我按下CTRL-C时,我会收到“Connection to the other side was lost in a non-clean fashion: Connection lost.”如何设置以便我知道何时发生KeyboardInterrupt,以便我可以正确清理并干净地断开连接?或者如果可能的话,如何实现更清洁的关闭方式,而不涉及CTRL-C?


甜,谷歌搜索“关闭之前扭曲”的第一次点击! - Claudiu
2个回答

31

如果你真的非常想要特别捕捉 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() 。无论何种方式导致反应器停止,它都会处理关闭事件触发器。


很完美!正如我所希望的那样顺利完成了。现在经过几个月的丑陋清理,终于变得漂亮而整洁了... - Claudiu

2

我不确定你是在谈论你编写的客户端还是服务器端。

无论如何,“CTRL-C”没有问题。

如果你正在编写一个应用程序服务器,请从twisted.application.service.Service进行子类化,并定义startServicestopService。维护活动协议实例的列表。使用stopService来浏览它们并优雅地关闭它们。

如果你有一个客户端,你也可以从Service进行子类化,但使用reactor.addSystemEventTrigger('before','shutdown',myCleanUpFunction)可能更简单,在这个函数中优雅地关闭连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接