Ловля / блокирующий SIGINT во время системного вызова

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

и процесс выходит полностью. Почему это происходит? Существует ли способ, которым я могу препятствовать тому, чтобы прерывание влияло на системный вызов?

8
задан Justin Johnson 10 June 2010 в 16:55
поделиться

1 ответ

socket.recv () вызывает базовую POSIX-совместимую функцию recv на уровне C, которая, в свою очередь, возвращает код ошибки. 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
8
ответ дан 5 December 2019 в 15:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: