Spec-Zone.ru › Python 3.14

signal — Установка обработчиков асинхронных событий

Исходный код: Lib/signal.py

Этот модуль предоставляет механизмы для использования обработчиков сигналов в Python.

Общие правила

Функция signal.signal() позволяет задавать пользовательские обработчики, которые будут выполняться при получении сигнала. Устанавливается небольшое число обработчиков по умолчанию: сигнал SIGPIPE игнорируется (поэтому ошибки записи в каналы и сокеты могут обрабатываться как обычные исключения Python), а сигнал SIGINT преобразуется в исключение KeyboardInterrupt, если родительский процесс не изменил его обработчик.

После установки обработчик для конкретного сигнала остаётся активным, пока его явно не сбросят (Python эмулирует интерфейс в стиле BSD независимо от базовой реализации). Исключение составляет обработчик сигнала SIGCHLD, который следует поведению базовой реализации.

На платформах WebAssembly сигналы эмулируются и поэтому ведут себя иначе. Некоторые функции и сигналы на этих платформах недоступны.

Выполнение обработчиков сигналов Python

Обработчик сигнала Python не выполняется внутри низкоуровневого обработчика сигнала (на C). Вместо этого низкоуровневый обработчик сигнала устанавливает флаг, который указывает виртуальной машине выполнить соответствующий обработчик сигнала Python позднее (например, при выполнении следующей инструкции байт-кода). Это имеет следующие последствия:

  • Обрабатывать синхронные ошибки, такие как SIGFPE или SIGSEGV, вызванные недопустимой операцией в коде на C, практически бессмысленно. Python вернётся из обработчика сигнала в код на C, который, скорее всего, снова вызовет тот же сигнал, из-за чего Python, по-видимому, зависнет. Начиная с Python 3.3, для сообщения о синхронных ошибках можно использовать модуль faulthandler.
  • Длительное вычисление, полностью реализованное на C (например, сопоставление с регулярным выражением в большом объёме текста), может выполняться без прерывания произвольное время независимо от полученных сигналов. Обработчики сигналов Python будут вызваны после завершения вычисления.
  • Если обработчик вызывает исключение, оно будет вызвано «из ниоткуда» в главном потоке. Обсуждение см. в примечании ниже.

Сигналы и потоки

Обработчики сигналов Python всегда выполняются в главном потоке Python главного интерпретатора, даже если сигнал был получен в другом потоке. Это означает, что сигналы нельзя использовать для межпоточного взаимодействия. Вместо этого можно использовать примитивы синхронизации из модуля threading.

Кроме того, устанавливать новый обработчик сигнала разрешено только главному потоку главного интерпретатора.

Предупреждение

Примитивы синхронизации, такие как threading.Lock, не следует использовать внутри обработчиков сигналов. Это может привести к неожиданным взаимным блокировкам.

Содержимое модуля

Изменено в версии 3.5: перечисленные ниже связанные константы signal (SIG*), handler (SIG_DFL, SIG_IGN) и sigmask (SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK) были преобразованы в enums (Signals, Handlers и Sigmasks соответственно). Функции getsignal(), pthread_sigmask(), sigpending() и sigwait() возвращают человекочитаемые enums в виде объектов Signals.

Модуль signal определяет три перечисления:

class signal.Signals

Коллекция констант SIG* и констант CTRL_* на основе enum.IntEnum.

Добавлено в версии 3.5.

class signal.Handlers

Коллекция констант SIG_DFL и SIG_IGN на основе enum.IntEnum.

Добавлено в версии 3.5.

class signal.Sigmasks

Коллекция констант SIG_BLOCK, SIG_UNBLOCK и SIG_SETMASK на основе enum.IntEnum.

Доступность: Unix.

Дополнительную информацию см. на страницах руководства sigprocmask(2) и pthread_sigmask(3).

Добавлено в версии 3.5.

В модуле signal определены следующие переменные:

signal.SIG_DFL

Это один из двух стандартных вариантов обработки сигнала; он просто выполняет действие по умолчанию для данного сигнала. Например, в большинстве систем действие по умолчанию для SIGQUIT — создать дамп памяти и завершить процесс, а для SIGCHLD — просто игнорировать сигнал.

signal.SIG_IGN

Это другой стандартный обработчик сигнала, который просто игнорирует полученный сигнал.

signal.SIGABRT

Сигнал аварийного завершения, отправляемый функцией abort(3).

signal.SIGALRM

Сигнал таймера, отправляемый функцией alarm(2).

Доступность: Unix.

signal.SIGBREAK

Прерывание с клавиатуры (CTRL + BREAK).

Доступность: Windows.

signal.SIGBUS

Ошибка шины (неверный доступ к памяти).

Доступность: Unix.

signal.SIGCHLD

Дочерний процесс остановлен или завершен.

Доступность: Unix.

signal.SIGCLD

Псевдоним для SIGCHLD.

Доступность: кроме macOS.

signal.SIGCONT

Продолжить выполнение процесса, если он в данный момент остановлен

Доступность: Unix.

signal.SIGFPE

Исключение при операциях с плавающей запятой. Например, деление на ноль.

См. также

При нулевом втором аргументе операции деления или взятия остатка возникает исключение ZeroDivisionError.

signal.SIGHUP

Обнаружен обрыв связи с управляющим терминалом или завершение управляющего процесса.

Доступность: Unix.

signal.SIGILL

Недопустимая инструкция.

signal.SIGINT

Прерывание с клавиатуры (CTRL + C).

Действие по умолчанию — возбуждение исключения KeyboardInterrupt.

signal.SIGKILL

Сигнал принудительного завершения.

Его нельзя перехватить, заблокировать или игнорировать.

Доступность: Unix.

signal.SIGPIPE

Обрыв канала: запись в канал, у которого нет читателей.

Действие по умолчанию — игнорировать сигнал.

Доступность: Unix.

signal.SIGPROF

Истекло время профилирующего таймера.

Доступность: Unix.

signal.SIGQUIT

Сигнал завершения работы терминала.

Доступность: Unix.

signal.SIGSEGV

Ошибка сегментации: недопустимая ссылка на память.

signal.SIGSTOP

Остановить выполнение (сигнал нельзя перехватить или игнорировать).

Доступность: Unix.

signal.SIGSTKFLT

Ошибка стека сопроцессора. Ядро Linux не отправляет этот сигнал: его можно отправить только из пользовательского пространства.

Доступность: Linux.

Доступно на некоторых архитектурах. Дополнительную информацию см. на странице руководства signal(7).

Добавлено в версии 3.11.

signal.SIGTERM

Сигнал завершения.

signal.SIGUSR1

Пользовательский сигнал 1.

Доступность: Unix.

signal.SIGUSR2

Пользовательский сигнал 2.

Доступность: Unix.

signal.SIGVTALRM

Истекло время виртуального таймера.

Доступность: Unix.

signal.SIGWINCH

Сигнал изменения размера окна.

Доступность: Unix.

signal.SIGXCPU

Превышен лимит процессорного времени.

Доступность: Unix.

SIG*

Все номера сигналов определены символически. Например, сигнал обрыва связи определен как signal.SIGHUP; имена переменных совпадают с именами, используемыми в программах на C и указанными в <signal.h>. На странице руководства Unix для «signal» перечислены существующие сигналы (в некоторых системах это signal(2), в других список приведен в signal(7)). Обратите внимание, что набор имен сигналов различается в разных системах; модуль определяет только имена, определенные в конкретной системе.

signal.CTRL_C_EVENT

Сигнал, соответствующий нажатию клавиш Ctrl+C. Этот сигнал можно использовать только с os.kill().

Доступность: Windows.

Добавлено в версии 3.2.

signal.CTRL_BREAK_EVENT

Сигнал, соответствующий нажатию клавиш Ctrl+Break. Этот сигнал можно использовать только с os.kill().

Доступность: Windows.

Добавлено в версии 3.2.

signal.NSIG

Число, на единицу превышающее наибольший номер сигнала. Используйте valid_signals(), чтобы получить допустимые номера сигналов.

signal.ITIMER_REAL

Уменьшает значение интервального таймера в реальном времени и по истечении времени отправляет сигнал SIGALRM.

signal.ITIMER_VIRTUAL

Уменьшает значение интервального таймера только во время выполнения процесса и по истечении времени отправляет SIGVTALRM.

signal.ITIMER_PROF

Уменьшает значение интервального таймера как во время выполнения процесса, так и во время работы системы от имени процесса. В сочетании с ITIMER_VIRTUAL этот таймер обычно используется для профилирования времени, которое приложение проводит в пользовательском пространстве и пространстве ядра. По истечении времени отправляется SIGPROF.

signal.SIG_BLOCK

Возможное значение параметра how функции pthread_sigmask(), указывающее, что сигналы следует заблокировать.

Добавлено в версии 3.3.

signal.SIG_UNBLOCK

Возможное значение параметра how функции pthread_sigmask(), указывающее, что блокировку сигналов следует снять.

Добавлено в версии 3.3.

signal.SIG_SETMASK

Возможное значение параметра how функции pthread_sigmask(), указывающее, что маску сигналов следует заменить.

Добавлено в версии 3.3.

Модуль signal определяет одно исключение:

exception signal.ItimerError

Возникает при ошибке в базовой реализации setitimer() или getitimer(). Ожидайте это исключение, если в setitimer() передан недопустимый интервальный таймер или отрицательное время. Это исключение является подклассом OSError.

Добавлено в версии 3.3: Раньше это исключение было подклассом IOError, который теперь является псевдонимом OSError.

Модуль signal определяет следующие функции:

signal.alarm(time)

Если time не равно нулю, функция запрашивает отправку процессу сигнала SIGALRM через time секунд. Любой ранее запланированный сигнал таймера отменяется (одновременно можно запланировать только один такой сигнал). В этом случае возвращается число секунд до отправки ранее запланированного сигнала таймера. Если time равно нулю, сигнал таймера не планируется, а любой ранее запланированный сигнал отменяется. Если возвращаемое значение равно нулю, сигнал таймера в данный момент не запланирован.

Доступность: Unix.

Дополнительную информацию см. на странице руководства alarm(2).

signal.getsignal(signalnum)

Возвращает текущий обработчик сигнала signalnum. Возвращаемое значение может быть вызываемым объектом Python или одним из специальных значений signal.SIG_IGN, signal.SIG_DFL или None. Здесь signal.SIG_IGN означает, что сигнал ранее игнорировался, signal.SIG_DFL означает, что ранее использовался способ обработки сигнала по умолчанию, а None означает, что предыдущий обработчик сигнала был установлен не из Python.

signal.strsignal(signalnum)

Возвращает описание сигнала signalnum, например «Прерывание» для SIGINT. Возвращает None, если у signalnum нет описания. Если signalnum недопустим, возбуждает исключение ValueError.

Добавлено в версии 3.8.

signal.valid_signals()

Возвращает множество допустимых номеров сигналов на этой платформе. Оно может быть меньше range(1, NSIG), если некоторые сигналы зарезервированы системой для внутреннего использования.

Добавлено в версии 3.8.

signal.pause()

Приостанавливает процесс до получения сигнала; после этого вызывается соответствующий обработчик. Ничего не возвращает.

Доступность: Unix.

Дополнительную информацию см. на странице руководства signal(2).

См. также sigwait(), sigwaitinfo(), sigtimedwait() и sigpending().

signal.raise_signal(signum)

Отправляет сигнал вызывающему процессу. Ничего не возвращает.

Добавлено в версии 3.8.

signal.pidfd_send_signal(pidfd, sig, siginfo=None, flags=0)

Отправляет сигнал sig процессу, на который ссылается файловый дескриптор pidfd. В настоящее время Python не поддерживает параметр siginfo; его значение должно быть None. Аргумент flags предусмотрен для будущих расширений; значения флагов пока не определены.

Дополнительную информацию см. на странице руководства pidfd_send_signal(2).

Доступность: Linux >= 5.1, Android >= уровень API 31 (build-time)

Добавлено в версии 3.9.

signal.pthread_kill(thread_id, signalnum)

Отправляет сигнал signalnum потоку thread_id — другому потоку в том же процессе, что и вызывающий. Целевой поток может выполнять любой код (Python или другой). Однако если целевой поток выполняет интерпретатор Python, обработчики сигналов Python будут выполняться главным потоком главного интерпретатора. Поэтому единственная цель отправки сигнала конкретному потоку Python — принудительно вызвать ошибку выполняющегося системного вызова InterruptedError.

Чтобы получить подходящее значение для thread_id, используйте threading.get_ident() или атрибут ident объектов threading.Thread.

Если signalnum равен 0, сигнал не отправляется, но проверка ошибок выполняется; это можно использовать, чтобы проверить, продолжает ли целевой поток работу.

Возбуждает событие аудита signal.pthread_kill с аргументами thread_id, signalnum.

Доступность: Unix.

Дополнительную информацию см. на странице руководства pthread_kill(3).

См. также os.kill().

Добавлено в версии 3.3.

signal.pthread_sigmask(how, mask)

Получает и/или изменяет маску сигналов вызывающего потока. Маска сигналов — это множество сигналов, доставка которых в данный момент заблокирована для вызывающего потока. Возвращает старую маску сигналов в виде множества сигналов.

Поведение вызова зависит от значения how следующим образом.

  • SIG_BLOCK: множество заблокированных сигналов становится объединением текущего множества и аргумента mask.
  • SIG_UNBLOCK: сигналы из mask удаляются из текущего множества заблокированных сигналов. Можно попытаться разблокировать сигнал, который не заблокирован.
  • SIG_SETMASK: множество заблокированных сигналов устанавливается равным аргументу mask.

mask — это множество номеров сигналов (например, {signal.SIGINT, signal.SIGTERM}). Чтобы получить полную маску со всеми сигналами, используйте valid_signals().

Например, signal.pthread_sigmask(signal.SIG_BLOCK, []) считывает маску сигналов вызывающего потока.

SIGKILL и SIGSTOP нельзя заблокировать.

Доступность: Unix.

Дополнительную информацию см. на страницах руководства sigprocmask(2) и pthread_sigmask(3).

См. также pause(), sigpending() и sigwait().

Добавлено в версии 3.3.

signal.setitimer(which, seconds, interval=0.0)

Устанавливает заданный интервальный таймер (один из signal.ITIMER_REAL, signal.ITIMER_VIRTUAL или signal.ITIMER_PROF), указанный параметром which, который сработает через seconds (допускается значение с плавающей точкой; в отличие от alarm()) и затем будет срабатывать каждые interval секунд (если interval не равен нулю). Интервальный таймер, указанный параметром which, можно сбросить, задав для seconds нулевое значение.

Когда срабатывает интервальный таймер, процессу отправляется сигнал. Отправляемый сигнал зависит от используемого таймера: signal.ITIMER_REAL отправляет SIGALRM, signal.ITIMER_VIRTUAL отправляет SIGVTALRM, а signal.ITIMER_PROF отправляет SIGPROF.

Старые значения возвращаются в виде кортежа: (delay, interval).

Попытка передать недопустимый интервальный таймер приведёт к возникновению ItimerError.

Доступность: Unix.

signal.getitimer(which)

Возвращает текущее значение заданного интервального таймера, указанного параметром which.

Доступность: Unix.

signal.set_wakeup_fd(fd, *, warn_on_full_buffer=True)

Задаёт файловый дескриптор пробуждения fd. Когда поступает сигнал, для которого программа зарегистрировала обработчик, номер сигнала записывается в fd одним байтом. Если вы не зарегистрировали обработчик сигналов, которые вас интересуют, в файловый дескриптор пробуждения ничего записано не будет. Библиотека может использовать это, чтобы пробудить вызов poll или select и дать возможность полностью обработать сигнал.

Возвращается прежний файловый дескриптор пробуждения (или -1, если пробуждение через файловый дескриптор не было включено). Если fd равен -1, пробуждение через файловый дескриптор отключается. Если значение не равно -1, fd должен быть неблокирующим. Библиотека должна удалять все байты из fd, прежде чем снова вызывать poll или select.

Если поддержка потоков включена, эту функцию можно вызывать только из главного потока главного интерпретатора; попытка вызвать её из других потоков приведёт к возникновению исключения ValueError.

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

В первом случае мы считываем данные из буфера файлового дескриптора, а значения байтов соответствуют номерам сигналов. Этот способ прост, но в редких случаях может возникнуть проблема: как правило, размер буфера файлового дескриптора ограничен, и если слишком много сигналов поступит за короткое время, буфер может заполниться, а некоторые сигналы могут быть потеряны. При использовании этого способа следует задать warn_on_full_buffer=True, чтобы при потере сигналов в stderr как минимум выводилось предупреждение.

Во втором случае файловый дескриптор пробуждения используется только для пробуждения, а фактические значения байтов игнорируются. В этом случае важно лишь то, пуст ли буфер файлового дескриптора; заполненный буфер не является проблемой. При использовании этого способа следует задать warn_on_full_buffer=False, чтобы не вводить пользователей в заблуждение ложными предупреждениями.

Изменено в версии 3.5: В Windows функция теперь также поддерживает дескрипторы сокетов.

Изменено в версии 3.7: Добавлен параметр warn_on_full_buffer.

signal.siginterrupt(signalnum, flag)

Изменяет поведение перезапуска системных вызовов: если flag равен False, системные вызовы будут перезапускаться при прерывании сигналом signalnum; в противном случае системные вызовы будут прерываться. Ничего не возвращает.

Доступность: Unix.

Дополнительную информацию см. на странице руководства siginterrupt(3).

Обратите внимание: установка обработчика сигнала с помощью signal() сбросит поведение перезапуска на прерываемое, неявно вызвав siginterrupt() со значением flag, равным true, для указанного сигнала.

signal.signal(signalnum, handler)

Задаёт обработчик сигнала signalnum — функцию handler. handler может быть вызываемым объектом Python, принимающим два аргумента (см. ниже), или одним из специальных значений signal.SIG_IGN и signal.SIG_DFL. Возвращается предыдущий обработчик сигнала (см. приведённое выше описание getsignal()). (Дополнительную информацию см. на странице руководства Unix signal(2).)

Если поддержка потоков включена, эту функцию можно вызывать только из главного потока главного интерпретатора; попытка вызвать её из других потоков приведёт к возникновению исключения ValueError.

Обработчик handler вызывается с двумя аргументами: номером сигнала и текущим кадром стека (None или объектом кадра; описание объектов кадров см. в описании в иерархии типов или в описаниях атрибутов модуля inspect).

В Windows функцию signal() можно вызывать только с SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM или SIGBREAK. В любом другом случае будет вызвано исключение ValueError. Обратите внимание: не во всех системах определён один и тот же набор имён сигналов; если имя сигнала не определено как константа уровня модуля SIG*, будет вызвано исключение AttributeError.

signal.sigpending()

Проверяет набор сигналов, ожидающих доставки вызывающему потоку (то есть сигналов, поступивших во время блокировки). Возвращает набор ожидающих сигналов.

Доступность: Unix.

Дополнительную информацию см. на странице руководства sigpending(2).

См. также pause(), pthread_sigmask() и sigwait().

Добавлено в версии 3.3.

signal.sigwait(sigset)

Приостанавливает выполнение вызывающего потока до доставки одного из сигналов, указанных в наборе сигналов sigset. Функция принимает сигнал (удаляет его из списка ожидающих сигналов) и возвращает номер сигнала.

Доступность: Unix.

Дополнительную информацию см. на странице руководства sigwait(3).

См. также pause(), pthread_sigmask(), sigpending(), sigwaitinfo() и sigtimedwait().

Добавлено в версии 3.3.

signal.sigwaitinfo(sigset)

Приостанавливает выполнение вызывающего потока до доставки одного из сигналов, указанных в наборе сигналов sigset. Функция принимает сигнал и удаляет его из списка ожидающих сигналов. Если один из сигналов в sigset уже ожидает обработки вызывающим потоком, функция немедленно возвращает информацию об этом сигнале. Обработчик доставленного сигнала не вызывается. Если функция прерывается сигналом, не входящим в sigset, она вызывает исключение InterruptedError.

Возвращаемое значение — объект, представляющий данные структуры siginfo_t, а именно: si_signo, si_code, si_errno, si_pid, si_uid, si_status, si_band.

Доступность: Unix.

Дополнительную информацию см. на странице руководства sigwaitinfo(2).

См. также pause(), sigwait() и sigtimedwait().

Добавлено в версии 3.3.

Изменено в версии 3.5: Теперь при прерывании сигналом, не входящим в sigset, функция выполняется повторно, если обработчик сигнала не вызывает исключение (обоснование см. в PEP 475).

signal.sigtimedwait(sigset, timeout)

Аналогична sigwaitinfo(), но принимает дополнительный аргумент timeout, задающий время ожидания. Если для timeout указано значение 0, выполняется проверка без ожидания. Если время ожидания истекло, возвращается None.

Доступность: Unix.

Дополнительную информацию см. на странице руководства sigtimedwait(2).

См. также pause(), sigwait() и sigwaitinfo().

Добавлено в версии 3.3.

Изменено в версии 3.5: Теперь при прерывании сигналом, не входящим в sigset, функция выполняется повторно с пересчитанным значением timeout, если обработчик сигнала не вызывает исключение (обоснование см. в PEP 475).

Примеры

Ниже приведён минимальный пример программы. В ней функция alarm() используется для ограничения времени ожидания при открытии файла; это полезно, если файл относится к последовательному устройству, которое может быть выключено, из-за чего вызов os.open() обычно зависал бы бесконечно. Решение состоит в том, чтобы установить 5-секундный таймер перед открытием файла; если операция длится слишком долго, будет отправлен сигнал таймера, а обработчик вызовет исключение.

import signal, os

def handler(signum, frame):
    signame = signal.Signals(signum).name
    print(f'Signal handler called with signal {signame} ({signum})')
    raise OSError("Couldn't open device!")

# Set the signal handler and a 5-second alarm
signal.signal(signal.SIGALRM, handler)
signal.alarm(5)

# This open() may hang indefinitely
fd = os.open('/dev/ttyS0', os.O_RDWR)

signal.alarm(0)          # Disable the alarm

Примечание о SIGPIPE

Перенаправление вывода программы в такие инструменты, как head(1), приведёт к отправке процессу сигнала SIGPIPE, когда получатель стандартного вывода преждевременно закроет соединение. В результате возникает исключение, например BrokenPipeError: [Errno 32] Broken pipe. Чтобы обработать такую ситуацию, оберните точку входа программы в блок перехвата этого исключения следующим образом:

import os
import sys

def main():
    try:
        # simulate large output (your code replaces this loop)
        for x in range(10000):
            print("y")
        # flush output here to force SIGPIPE to be triggered
        # while inside this try block.
        sys.stdout.flush()
    except BrokenPipeError:
        # Python flushes standard streams on exit; redirect remaining output
        # to devnull to avoid another BrokenPipeError at shutdown
        devnull = os.open(os.devnull, os.O_WRONLY)
        os.dup2(devnull, sys.stdout.fileno())
        sys.exit(1)  # Python exits with error code 1 on EPIPE

if __name__ == '__main__':
    main()

Не задавайте для сигнала SIGPIPE действие по умолчанию SIG_DFL, пытаясь избежать исключения BrokenPipeError. Это приведёт к неожиданному завершению программы при любом прерывании соединения с сокетом, пока программа продолжает в него записывать.

Примечание об обработчиках сигналов и исключениях

Если обработчик сигнала вызывает исключение, оно будет передано главному потоку и может возникнуть после выполнения любой инструкции байткода. В частности, KeyboardInterrupt может возникнуть в любой момент выполнения программы. Большинство кода Python, включая стандартную библиотеку, невозможно сделать устойчивым к этому, поэтому KeyboardInterrupt (или любое другое исключение, вызванное обработчиком сигнала) в редких случаях может привести программу в неожиданное состояние.

Чтобы проиллюстрировать эту проблему, рассмотрим следующий код:

class SpamContext:
    def __init__(self):
        self.lock = threading.Lock()

    def __enter__(self):
        # If KeyboardInterrupt occurs here, everything is fine
        self.lock.acquire()
        # If KeyboardInterrupt occurs here, __exit__ will not be called
        ...
        # KeyboardInterrupt could occur just before the function returns

    def __exit__(self, exc_type, exc_val, exc_tb):
        ...
        self.lock.release()

Для многих программ, особенно тех, которым достаточно завершиться при возникновении KeyboardInterrupt, это не проблема. Однако сложным приложениям или приложениям с высокими требованиями к надёжности следует избегать вызова исключений из обработчиков сигналов. Им также следует избегать перехвата KeyboardInterrupt в качестве способа корректного завершения работы. Вместо этого следует установить собственный обработчик SIGINT. Ниже приведён пример HTTP-сервера, который не допускает KeyboardInterrupt:

import signal
import socket
from selectors import DefaultSelector, EVENT_READ
from http.server import HTTPServer, SimpleHTTPRequestHandler

interrupt_read, interrupt_write = socket.socketpair()

def handler(signum, frame):
    print('Signal handler called with signal', signum)
    interrupt_write.send(b'\0')
signal.signal(signal.SIGINT, handler)

def serve_forever(httpd):
    sel = DefaultSelector()
    sel.register(interrupt_read, EVENT_READ)
    sel.register(httpd, EVENT_READ)

    while True:
        for key, _ in sel.select():
            if key.fileobj == interrupt_read:
                interrupt_read.recv(1)
                return
            if key.fileobj == httpd:
                httpd.handle_request()

print("Serving on port 8000")
httpd = HTTPServer(('', 8000), SimpleHTTPRequestHandler)
serve_forever(httpd)
print("Shutdown...")

© 2001 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/library/signal.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API