在系统调用期间捕获/阻止 SIGINT

2023-11-24

我编写了一个网络爬虫,我希望能够通过键盘停止它。我不希望程序在我中断它时死掉;它需要首先将数据刷新到磁盘。我也不想抓KeyboardInterruptedException,因为持久数据可能处于不一致的状态。

我当前的解决方案是定义一个信号处理程序来捕获SIGINT并设置一面旗帜;主循环的每次迭代都会在处理下一个 url 之前检查此标志。

但是,我发现如果系统恰好正在执行socket.recv()当我发送中断时,我得到这个:

^C
Interrupted; stopping...  // indicates my interrupt handler ran
Traceback (most recent call last):
  File "crawler_test.py", line 154, in <module>
    main()
  ...
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py", line 397, in readline
    data = recv(1)
socket.error: [Errno 4] Interrupted system call

并且进程完全退出。为什么会出现这种情况?有没有办法可以防止中断影响系统调用?


socket.recv()调用底层 POSIX 兼容的recvC 层中的函数,该函数又会返回错误代码EINTR当进程收到一个SIGINT在等待传入数据时recv()。此错误代码可用于 C 端(如果您使用 C 进行编程)来检测recv()返回不是因为套接字上有更多可用数据,而是因为进程收到了SIGINT。无论如何,这个错误代码会被 Python 转换为异常,并且由于它永远不会被捕获,因此它会使用您看到的回溯来终止您的应用程序。解决办法很简单,就是抓住socket.error,检查错误代码是否等于errno.EINTR,默默地忽略异常。像这样的东西:

import errno

try:
    # do something
    result = conn.recv(bufsize)
except socket.error as (code, msg):
    if code != errno.EINTR:
        raise
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在系统调用期间捕获/阻止 SIGINT 的相关文章

随机推荐