python - 在系统调用期间捕获/阻塞 SIGINT

标签 python unix signals interrupt system-calls

我已经编写了一个网络爬虫,我希望能够通过键盘停止它。我不希望程序在我中断时死掉;它需要先将其数据刷新到磁盘。我也不想捕获 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() 在 C 层调用底层的 POSIX 兼容的 recv 函数,后者将返回一个错误代码 EINTR 当进程在 recv() 中等待传入数据时收到 SIGINT。此错误代码可用于 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

关于python - 在系统调用期间捕获/阻塞 SIGINT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3016369/

相关文章:

python - 重叠圆的面积

python - 如何确保在 pd.merge 期间不会丢失任何行

python - 为什么 if-else 表达式的第二个条件中的尾随逗号导致第一个条件被转换为元组

Python:从两个列表创建可能的子列表,其中顺序不变

linux - 按 ID 拆分内容(第一列)并根据格式生成新的数据文件

ruby - 在 Ruby 中创建一个双叉守护进程

c - 超过超时限制后未从 alarm() 触发信号处理程序

unix - 如何在vim中在新窗口中打开新文件

c++ - fork 、信号以及它们如何与 C 中的全局变量交互

c - 使用 C 在 OS X 上确定进程是否暂停(使用 SIGSTOP)