Skip to content

Home Администрирование Запуск демона
Запуск демона

Работа с демонами - это данность для любого, кто потратил на операционную систему UNIX больше времени, чем необходимо для беглого знакомства. Демоны вbinолняют практически любые операции - от обработки запросов до пересылки файлов на принтер (например, lpd), приема запросов HTTP и передачи файлов (например, демон httpd вебсервера Apache).

Так что же такое демон? Часто под демоном понимают вbinолняющийся в фоновом режиме процесс, который не имеет управляющего терминала. Если вы знакомы с механизмом управления заданиями в UNIX, у вас может сложиться мнение, что добавление символа & в конце команды создаст демона. Или нажатие комбинации Ctrl-Z после запуска процесса с последующей командой ьg создаст демона. В обоих случаях вы получите фоновые процессы, но ни один из этих способов не отрывает процесс от командной оболочки и не лишает его управляющего терминала (возможно, принадлежащего процессу командной оболочки). Итак, три основных признака демона: ввыполнение в фоновом режиме, отсутствие связи с процессом, запустившим его, и отсутствие управляющего терминала. Процесс, запущенный в фоновом режиме при помощи механизма управления заданиями, отвечает только первому требованию.

Ниже приводится фрагмент программного кода, в котором определяется функция daemonize(). Она превращает вызывающий ее процесс в демона - в том смысле, в каком говорилось в предыдущем параграфе. Эта функция была взята из рецепта «Forking a Daemon Process on Unix», который приводится во втором издании книги Дэвида Ашера (David Asher) «Python Cookbook» (O'Reilly) на страницах 388-389. Этот программный код достаточно близко следует рекомендациям, которые предлагает Ричард Стивене (Richard Stevens) в своей книге «UNIX Network Programming: The Sockets Networking API» (O'Reilly) в качестве «правильного» способа создания демона. Для тех, кто не знаком с книгой Стивенса, заметим, что она обычно рассматривается как справочник по сетевому программированию, а также как руководство по созданию демонов в UNIX. Исходный текст функции приводится в примере 10.26.

Пример 10.26. Функция daemonize

Первое, что делает эта функция, - с помощью функции f ork() производит ветвление процесса. В этом случае создается копия работающего процесса, и эта копия рассматривается как «дочерний» процесс, а оригинал - как «родительский» процесс. После создания копии родительский процесс может завершить свою работу. Для этого проверяется идентификатор процесса pid после ветвления. Если идентификатор представлен положительным числом, это означает, что вbinолняется родительский процесс. Если вы никогда не программировали ветвление процессов с помощью функции fork(), это может показаться вам странным. После возврата из функции os.fork() в системе появляется две копии одного и того же работающего процесса. Обе они проверяют код, возвращаемый функцией fork(), который в дочернем процессе будет иметь значение 0, а в родительском процессе - соответствовать идентификатору процесса. Любое ненулевое значение возвращается только родительскому процессу, который должен завершить работу. Если здесь возникло исключение, процесс просто завершается. Если этот сценарий вызывается из интерактивной командной оболочки (такой как bash), вы в этот момент вернетесь в строку приглашения к вводу, потому что тот процесс, который вы запускали, только что завершил работу. Но дочерний процесс продолжает свою работу.

Затем процесс изменяет рабочий каталог на / (os.chdir("/"), устанавливает маску в значение 0 (os. umask(0)) и создает новый сеанс (os. set -sid()). Изменение каталога на / переводит процесс демона в каталог, который всегда существует. Дополнительное преимущество, которое дает операция перехода в каталог /, заключается в том, что дрлгожи-вущий процесс не будет препятствовать возможности отмонтировать файловую систему, если получилось, что он был запущен из каталога в файловой системе, которую вы пожелаете отмонтировать. Затем процесс изменяет свою маску режима создания файлов на маску с более широкими правами. Если демон должен создавать файлы с правами доступа для группы, унаследованная маска с более ограниченными правами может давать отрицательный эффект. Последнее из этих трех действий (os. setsid()), пожалуй, наименее знакомо большинству читателей. Функция setsid() вbinолняет множество действий. Во-первых, она делает процесс лидером нового сеанса. Далее, она делает процесс лидером новой группы процессов. Наконец, пожалуй, самое важное для демонов - она лишает процесс управляющего терминала. Факт отсутствия управляющего терминала означает, что процесс не может пасть жертвой неумышленных (или преднамеренных) операций с механизмом управления заданиями с какого-либо терминала. Для долгоживущих процессов, таких как демоны, очень важно исключить возможность прерывания работы.

Но самое интересное на этом не заканчивается. После вызова функции os.setsid0 производится повторное ветвление. Первое ветвление процесса и вызов функции setsid() лишь готовят почву для второго ветвления - они отсоединяют процесс от какого-либо управляющего терминала и делают его лидером сеанса. Второе ветвление означает, что получившийся процесс не может быть лидером сеанса, а также то, что процесс не может приобрести управляющий терминал. Второе ветвление не является обязательной процедурой и вbinолняется больше из предосторожности. Без второго ветвления процесс мог бы приобрести управляющий терминал, открыв любое терминальное устройство без флага 0_NOCTTY.

Последнее, что делает функция, - вbinолняет очистку файлов и производит их реорганизацию. Выталкивается информация в стандартных потоках вывода и вывода сообщений об ошибках (sys.stdout и sys. stderr). Тем самым гарантируется вывод информации, которая еще не была выведена. Функция daemonize() позволяет вызывающей программе определять файлы, которые будут играть роль потоков stdin, stdout и stderr. По умолчанию в качестве всех трех файлов используется устройство /clev/null. В этом месте функция принимает либо указанные пользователем файлы, либо значения по умолчанию и устанавливает стандартный ввод, стандартный вывод и стандартный вывод сообщений об ошибках в соответствие этим файлам.

Как можно использовать функцию daemonize()? Предположим, что у нас имеется программный код демона в виде сценария daemonize. py. В примере 10.27 приводится пример сценария, использующего эту функцию.

Пример 10.27, Использование функции daemonize()

Этот сценарий сначала переходит в режим демона, определяя при этом, что в качестве стандартного вывода будет использоваться файл / tmp / stdout . log , а в качестве стандартного вывода сообщений об ошибках будет использоваться файл / tmp /' stderr . log . Затем в течение 20 секунд, с интервалами в 1 секунду между проверками, он отслеживает текущее время. Если время, выраженное в секундах, делится на пять без остатка, производится запись сообщения в поток стандартного вывода сообщений об ошибках. Если время не делится на пять, производится запись сообщения в поток стандартного вывода. Так как процесс использует файлы / tmp / stdout . log и / tmp / stderr . log в качестве стандартного вывода и стандартного вывода сообщений об ошибках, соответственно, то мы имеем возможность наблюдать эти сообщения после запуска этого примера...

И ниже приводится результат работы примера:

Сразу же после запуска сценария происходит возврат в строку приглашения к вводу:

Это действительно очень простой пример написания демона, но мы надеемся, что он наглядно демонстрирует некоторые базовые понятия. Вы можете использовать функцию daemonize() для создания демона, который следит за состоянием каталога, вbinолняет мониторинг сети, сетевых серверов и всего, что угодно, и работает продолжительное (или неопределенно продолжительное) время.

Хотелось бы надеяться, что эта статья продемонстрировала, насколько широкими и мощными возможностями обладает язык Python для работы с процессами. В языке Python реализован весьма изящный и сложный прикладной интерфейс для работы с потоками выполнения, но при этом всегда полезно помнить о существовании GIL. Если вы связаны с вводом-выводом, тогда зачастую эта блокировка не является проблемой, но если вам требуется загрузить работой несколько процессоров, то лучше будет использовать несколько процессов. Некоторые считают, что процессы предпочтительнее, чем потоки, даже если бы не было блокировки GIL. Главная причина появления такого мнения состоит в том, что отладка многопоточного программного кода может превратиться в кошмар.

Наконец, будет совсем не лишним поближе познакомиться с модулем subprocess, если вы с ним еще не знакомы. subprocess — это универсальный модуль, построенный по принципу «все в одном», предназначенный для работы с... ну. пусть будет, с подпроцессами.

Комментарии (0)

RSS feed Comments

Написать комментарий

smaller | bigger

busy
 

Регистрация




Top