我正在尝试处理Python脚本中的信号接收,以进行清理并正常退出。该脚本利用了许多socket
连接,我意识到这些连接可能在发出信号期间正在运行,因此需要对此进行调查。具体来说,等待网络响应的操作将立即退出,以便程序可以及时响应信号。
幸运的是,据我的研究使我相信,似乎在任何系统调用(例如在socket.connect()
中,立即调用信号处理程序将被中断。此外,在Python中,如果信号处理程序引发异常,则该异常会从进行系统调用的代码中传播出去。
因此,我准备了以下代码来测试在出现信号的情况下是否等待网络响应。我们通过尝试在无法响应的端口上连接Google来模拟长时间的网络等待/超时。在等待期间,异步引发退出信号(CTRL_C_EVENT
,该信号由SIGINT处理,因为我当前正在使用Windows)。信号处理程序将被调用并通过SystemExit
引发sys.exit()
异常,然后应将其抛出socket.connect()
并加以捕获,然后程序正常退出。
import os
import signal
import socket
import sys
import threading
import time
def kill():
print("Raising signal at {}".format(time.time()))
os.kill(os.getpid(), signal.CTRL_C_EVENT)
def handler(signo, frame):
print("Handling signal at {}".format(time.time()))
sys.exit()
signal.signal(signal.SIGINT, handler)
t = threading.Timer(5, kill)
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(10)
print("Connecting at {}".format(time.time()))
t.start()
s.connect(("www.google.com", 81))
print("Connected at {}".format(time.time()))
except SystemExit as e:
print("Caught SystemExit at {}".format(time.time()))
raise e
我希望程序会输出以下内容:
Connecting at <some time A>
Raising signal at <~5s after A>
Handling signal at <~5s after A>
Caught SystemExit at <~5s after A>
<program exits>
但是我实际得到的一个例子是:
Connecting at 1544985636.4006333
Raising signal at 1544985641.4017904
Handling signal at 1544985646.4649496
<program exits>
您可以看到,不仅SystemExit
异常神奇地消失在某个地方,而且信号处理程序在发出信号后5秒钟被调用!似乎socket.connect
吞噬了信号然后超时,而不是立即中断(但是由于某种原因没有引发异常吗?)。
这种奇怪行为的原因是什么?收到信号后,如何获得退出socket.connect()
的预期行为?