Как написать демона linux
Перевод Linux Daemon HOWTO
Как написать демон в Linux
1. Введение: что есть демон?
3. Планирование вашего демона
* 3.1 Что необходимо сделать?
* 3.2 Насколько интерактивные?
4. Базовая структура демона
* 4.1 Ответвление от родительского процесса
* 4.2 Изменение маски файла (Umask)
* 4.3 Открытие журналов на запись
* 4.4 Создание уникального ID сессии (SID)
* 4.5 Изменение рабочего каталога
* 4.6 Закрытие стандартных файловых дескрипторов
5. Реализация кода демона
* 5.1 Инициализация
* 5.2 Большой Цикл
6. Собираем все вместе
* 6.1 Законченный пример
1. Введение: что есть демон?
Демон (или служба) является фоновым процессом, который разработан специально для автономной работы, с минимальным вмешательством пользователя или вообще без него. HTTP-демон (httpd) веб-сервера Apache является одним из примеров таких процессов. Он работает в фоновом режиме, слушая специфичные порты и обслуживая страницы или выполняя скрипты, в зависимости от вида запроса.
Создание демона в Linux включает в себя соблюдение набора специфических правил в определенном порядке. Знание того как они работают поможет вам понять как демоны работают в пространстве пользователя Linux, но при этом также могут использовать вызовы ядра. На самом деле, совсем немного демонов взаимодействует с модулями ядра, которые работают с аппаратными устройствами, такими как платы внешних контроллеров, принтеров и КПК. Они являются одним из фундаментальных строительных блоков в Linux и дают невероятные гибкость и производительность системе в целом.
В процессе повествования будет разработан очень простой демон на языке C. По мере продвижения по документу будет добавляться все больше кода, показывающего правильный порядок разработки, необходимый для запуска и работы демона.
Прежде всего, для разработки демонов в вашей Linux системе должны быть установлены следующие пакеты:
* GCC 3.2.2 или выше
* библиотеки и заголовочные файлы для разработки в Linux
Если в вашей системе они еще не установлены (что вряд ли, но все равно проверьте), то они понадобятся вам для реализации примеров из этого документа. Чтобы узнать версию установленного в вашей системе GCC, скомандуйте:
3. Планирование вашего демона
3.1 Что необходимо сделать?
Демон должен делать только одну вещь и делать ее хорошо. Эта одна вещь может быть такой же сложной как управление сотнями почтовых ящиков во множестве доменов или такой же простой как формирование отчета и вызов sendmail для оправки этого отчета админу.
В любом случае вы должны хорошо представлять себе то, что должен делать ваш демон. Если планируется взаимодействие с другими демонами, разрабатываемыми и вами, и не вами, то это тоже необходимо учитывать при планировании.
3.2 Насколько интерактивные?
Демоны не должны общаться с пользователем напрямую через терминал. На самом деле, демон вообще не должен напрямую общаться с пользователем. Все общение должно производиться через определенный интерфейс (который может позволять, а может и не позволять запись), который может быть сложным как GTK+ GUI или простым как набор сигналов.
4. Базовая структура демона
Когда демон запускается, он выполняет некоторую низкоуровневую работу для подготовки себя к основной работе. Первая включает в себя несколько шагов:
* Отделение (ответвление, fork) от родительского процесса
* Изменение файловой маски (umask)
* Открытие любых журналов на запись
* Создание уникального ID сессии (SID)
* Изменение текущего рабочего каталога на безопасное место
* Закрытие стандартных файловых дескрипторов
* Переход к коду собственно демона
4.1 Отделение от родительского процесса
Демон запускается либо самой системой, либо пользователем в терминале или скрипте. Во время запуска его процесс ничем не отличается от любого другого процесса в системе. Чтобы сделать его по-настоящему автономным, нужно создать дочерний процесс, в котором будет выполняться код демона. Это называется форком и для этого используется функция fork():
Отметим здесь проверку успешного завершения вызова fork(). При разработке демона необходимо делать код максимально стабильным. На самом деле, большую часть всего кода демона составляют именно проверки на ошибки.
Если получение PID от fork() совершилось успешно, то родительский процесс должен изящно завершиться. Это может показаться странным для всех, кто такого еще не видел, но после ответвления дочерний процесс продолжает выполнение остального кода с этого места.
4.2 Изменение файловой маски (Umask)
Чтобы иметь возможномть писать в любые файлы (включая журналы), созданные демоном, файловая маска (umask) должна быть изменена так, чтобы они могли быть записаны или прочитаны правильным образом. Это похоже на выполнение umask из командной строки, но мы прагматично делаем это здесь при помощи функции umask():
Через установку umask в 0 мы получим полный доступ к файлам, созданным демоном. Даже если вы не планируете использовать какие-либо файлы вообще, установка umask остается хорошей идеей просто на случай доступа к файлам на файловой системе.
4.3 Открытие журналов на запись
Эта действие опционально, но все-таки рекомендуется открыть где-нибудь в системе файл журнала на запись. Это можно сделать даже только для того, чтобы вы имели возможность посмотреть на отладочную информацию от демона.
4.4 Создание уникального ID сессии (SID)
С этого места для нормальной работы дочерний процесс должен получить уникальный SID от ядра. Иначе дочерний процесс станет сиротой. Тип pid_t, объявленный в предыдущем разделе, также используется для создания нового SID для дочернего процесса:
Как видим, функция setsid() возвращает данные того же типа что и fork(). Чтобы проверить что функция создала SID для дочернего процесса мы можем использовать аналогичную процедуру проверки на ошибки.
4.5 Изменение рабочего каталога
Текущий рабочий каталог нужно сменить на некоторое место, гарантированно присутствующее в системе. Поскольку многие дистрибутивы Linux не полностью следуют стандарту иерархии файловой системы Linux (FHS, Filesystem Hierarchy Standard), то в системе гарантированно присутствует только корень файловой системы (/). Сменить каталог можно при помощи функции chdir():
4.6 Закрытие стандартных файловых дескрипторов
Одним из последних шагов в стартовой настройке демона является закрытие стандартных файловых дескрипторов (STDIN, STDOUT, STDERR). Поскольку демон не может использовать терминал, эти файловые дескрипторы излишни и создают угрозу безопасности. Закрыть их можно при помощи функции close():
Использование определенных для файловых дескрипторов констант является хорошей идеей, поскольку улучшает переносимость.
5. Разработка кода демона
5.1 Инициализация
На данном этапе вы уже в основном сообщили Linux о том что вы демон, так что сейчас самое время написать код самого демона. Инициализация является первым шагом на этом пути. Поскольку возможно существование множества разных функций, которые могут быть вызваны здесь для настройки вашего демона, я не буду углубляться в этот вопрос.
Важный момент здесь в том, что при инициализации чего-нибудь в демоне необходимо применять те же методы обнаружения и обработки ошибок. Будьте болтливы («verbose») насколько это возможно при записи в syslog или в ваши собственные журналы. Отладка демона может затрудниться при недостатке информации о его состоянии.
5.2 Большой Цикл
Основной код демона обычно находится внутри бесконечного цикла. Технически это не бесконечный цикл конечно, но он организован как бесконечный:
Типичный цикл обычно является циклом while, который имеет бесконечное условие завершения с вызовом sleep при необходимости выполнения через фиксированные интервалы.
Представьте себе это стуком сердца: когда ваше сердце сжимается, оно выполняет несколько задач, затем ожидает следующего сжатия. Многие демоны следуют этой методологии.
6. Собираем все вместе
6.1 Законченный пример
Приведенное ниже является законченным примером демона и иллюстрирует все шаги, необходимые для запуска и работы. Для его выполнения просто скимпилируйте при помощи gcc и запустите на выполнение из командной строки. Для завершения выясните его PID и воспользуйтесь командой kill.
Я также задействовал подходящие заголовочные файлы для взаимодействия с syslog’ом, использование которого рекомендуется как минимум для записи в журнал информации о запуске/останове/паузе/завершении, в дополнение к использованию ваших собственных журналов через вызовы функций fopen()/fwrite()/fclose().
Вы можете использовать этот скелет для разработки ваших собственных демонов. Не забывайте вести журналы событий (или используйте возможности syslog) и кодируйте надежно, кодируйте надежно, кодируйте надежно!
Русские Блоги
Написание демона Linux
Linux-демон
I. Базовые знания
1) тип процесса, процессы условно делятся на три категории
(1) интерактивный процесс
(2) Процесс пакетной обработки
2) Характеристики демона
(1) Режим работы : Демон, также известный как Daemon Процессы в Linux Фоновый сервис Процесс. Периодически выполняйте определенные задачи или ожидайте обработки определенных событий. Системы Linux имеют много демонов, большинство из них обслуживание Все реализованы с использованием демонов.
Например: как наши tftp, samba, nfs и другие связанные сервисы. В то же время большинство серверов в Linux реализованы с использованием демонов.
Например, интернет-сервер inetd, веб-сервер httpd и т. Д.
(2 ) Жизненный цикл: Демоны работают в течение длительного времени, часто запускаются при запуске системы и не завершаются, пока система не выключится
(3 ) Демон не зависит от терминала: Очевидно, что процессы, запущенные из терминала, будут подключены к этому терминалу, этот терминал называется управляющим терминалом этих процессов. Когда терминал управления закрыт, соответствующий процесс автоматически закрывается. Когда мы обычно пишем процессы, программа с бесконечным циклом закрывает терминал и закрывает нашу программу, но для процесса-демона его демон жизненного цикла должен преодолеть это ограничение: он запускается с самого начала до полной остановки системы. Таким образом, демон не может зависеть от терминала.
Посмотрите на демонов в системе
-X: показать процессы без управления терминалом
-J: Показать информацию о задании (отображаемые столбцы): идентификатор сеанса (SID), идентификатор группы процессов (PGID), терминал управления (TTY), идентификатор группы процессов терминала (TRGID)
Как идентифицировать демона:
Например, процесс планирования работы cron
В-четвертых, концепции, относящиеся к сеансу: группа процессов, группа процессов переднего плана, группа фоновых процессов, сеанс, терминал управления
1) Группа процессов
2) Сессия
3) Терминал управления
Сессия обычно имеет управляющий терминал для выполнения IO Операция. Терминал, в который входит пользователь, становится управляющим терминалом для сеанса. Процесс лидера сеанса, который устанавливает соединение с управляющим терминалом, также называетсяКонтроль процесса (controlling process) 。 Для сеанса может быть только один управляющий терминал.
4) группа процессов переднего плана
Процессы в этой группе процессов могут выполняться на терминальном устройстве. Читать, писать Группа процессов операции.
5) группа фоновых процессов
Процессы в этой группе процессов могут сообщать только терминальному устройству. Написать 。
Каждый сеанс имеет одну и только одну группу процессов переднего плана, но будет 0 Одна или несколько групп фоновых процессов.
6) Идентификатор группы процессов терминала
Например
$ ping 127.0.0.1 | grep icmp > temp & Передайте две инструкции вместе и поместите на задний план
$ ping 127.0.0.1 | grep icmp Запустить на переднем плане
Посмотреть результаты
Мы узнали
После выполнения Ctrl + C в терминале
Пять шагов написания Linux-демона
Step1: Создать дочерний процесс, родительский процесс завершен
По сути Сделать ini t Процесс становится родителем вновь порожденного процесса. вызов fork После того, как функция создает дочерний процесс, она немедленно завершает работу родительского процесса. В результате дочерний процесс станет сиротским процессом и будет init Процесс вступает во владение, и в то же время новый сгенерированный процесс будет работать в фоновом режиме, используя описанный ранее родительский процесс, ядро автоматически поручит дочернему процессу init Принцип.
if (pid > 0) /* Родительский процесс завершается */
Step2: Выйдите из терминала управления и создайте новый сеанс
Этот шаг является наиболее важным шагом в создании демона, хотя реализация очень проста, но она очень важна.
Ps: Если вызывающий процесс уже является лидером группы процессов, эта функция возвращает ошибку. Вспомните, что мы сделали, чтобы не оказаться в такой ситуации? Первым шагом является вызов fork, затем родительский процесс завершается, а дочерний процесс продолжается. Поскольку дочерний процесс наследует идентификатор группы процессов родительского процесса, а его идентификатор процесса назначается заново, они не могут быть равны, что гарантирует, что дочерний процесс не является лидером группы процессов.
Шаг 3: изменить текущий рабочий каталог
Этот шаг также необходим. Дочерний процесс, созданный с помощью fork (), наследует текущий рабочий каталог родительского процесса. Поскольку файловая система (такая как «/ mnt / usb» и т. Д.), В которой находится текущий каталог, не может быть размонтирована во время выполнения процесса, это вызовет много проблем для будущего использования. Поэтому обычной практикой является использование «/» в качестве текущего рабочего каталога демона, что позволяет избежать вышеуказанных проблем. Конечно, если у вас есть особые потребности, вы также можете изменить текущий рабочий каталог на другой путь, например / tmp. Распространенной функцией для изменения рабочего каталога является chdir ().
Step4: Сбросить маску прав доступа к файлу
Процесс наследует маску создания файла от родительского процесса, который ее создал. Он может изменять биты доступа к файлам, созданным демоном. Чтобы предотвратить это, очистите маску создания файла:
Step5: Отключить файловые дескрипторы
Процесс наследует дескрипторы открытых файлов от родительского процесса, который его создал. Если не закрыть, системные ресурсы будут потрачены впустую, что приведет к размонтированию файловой системы, в которой расположен процесс, и к непредвиденным ошибкам:
int getdtablesize(void);
Возвращает: максимальное количество файловых дескрипторов, открытых процессом (1024)
Запретить процессам повторное открытие терминала управления
Теперь процесс стал главой бессессионного терминала. Но он может повторно открыть контрольный терминал. Вы можете помешать процессу повторно открыть управляющий терминал, сделав процесс больше не лидером сеанса:
if(pid=fork())
exit (0); // Завершаем первый дочерний процесс, и второй дочерний процесс продолжается (второй дочерний процесс больше не является лидером сеанса)
Русские Блоги
Процесс системного программирования Linux (восемь): подробное объяснение и создание процесса демона, использование daemon ()
1. Обзор Daemon
Демоны, как правило, начинают работать при запуске системы, и если их не принудительно завершить, в противном случае продолжайте работу, пока система не будет выключена. Демоны часто запускаются с привилегиями суперпользователя (root), потому что они используют специальные порты (1-1024) или получают доступ к определенным специальным ресурсам.
Имя демона обычно заканчивается на d, например sshd, xinetd, crond и т. Д.
Во-вторых, шаги для создания демона
Сначала мы должны понять некоторые основные понятия:
Функция setsid () может установить период диалога:
Если процесс, вызывающий setsid, не является лидером группы процессов, эта функция создает новый сеанс 。
(1) Этот процесс становится первым процессом периода диалога
(2) Этот процесс становится лидером процесса новой группы процессов.
(3) В этом процессе нет управляющего терминала. Если у процесса есть управляющий терминал до вызова setsid, контакт с терминалом освобождается. Если процесс является лидером группы процессов, эта функция возвращает ошибку.
(4) Чтобы убедиться в этом, мы сначала вызываем fork (), а затем exit (), в это время работает только дочерний процесс.
Теперь давайте рассмотрим шаги, необходимые для создания демона:
Общие шаги для написания демона:
(1) Выполнить форк и выйти из родительского процесса;
(2) вызовите функцию setsid в дочернем процессе, чтобы создать новый сеанс;
(3) вызовите функцию chdir в дочернем процессе, чтобы сделать корневой каталог «/» рабочим каталогом дочернего процесса;
(4) Вызовите функцию umask в подпроцессе и установите для umask процесса значение 0;
(5) Закройте все ненужные файловые дескрипторы в дочернем процессе
Три, создайте демон
Перед созданием давайте разберемся с использованием setsid ():
// Вызывающий процесс должен быть не текущим лидером группы процессов. После вызова генерируется новый период сеанса, и в период сеанса существует только одна группа процессов, и лидер группы процессов является вызывающим процессом без управляющего терминала. И идентификатор сеанса установлен на PID вызывающего процесса
Теперь создайте демон согласно приведенным выше шагам:
Следующая программа предназначена для создания демона, а затем с помощью этого демона каждую минуту записывает текущее время в файл daemon.log
Результаты показывают, что когда я выполняю a.out как обычный пользователь, вновь созданный демон не появляется в таблице процессов, но когда я выполняю как пользователь root, он успешно выполняется, и файл daemon.log создается в каталоге /, После просмотра кошки это действительно пишется раз в минуту. Почему он может выполняться только пользователем root, потому что когда мы создали процесс демона, мы переключили текущий каталог на каталог my /, поэтому, когда я позже создаю файл daemon.log, он фактически находится в каталоге /. Разрешения, может быть, вы спросите, почему это не так? На самом деле, есть ошибка, но мы закрыли стандартный ввод и перенаправили на / dev / null при создании демона, поэтому мы не можем увидеть сообщение об ошибке.
В-четвертых, используйте библиотечную функцию daemon () для создания демона
Фактически, мы можем использовать функцию daemon () для создания процесса-демона, прототип функции:
int daemon(int nochdir, int noclose);
DESCRIPTION
The daemon() function is for programs wishing to detach themselves from
the controlling terminal and run in the background as system daemons.
If nochdir is zero, daemon() changes the process’s current working
directory to the root directory («/»); otherwise,
If noclose is zero, daemon() redirects standard input, standard output
and standard error to /dev/null; otherwise, no changes are made to
these file descriptors.
Функция: Создать демон
nochdir: = 0 меняет текущий каталог на «/»
noclose: = 0 перенаправить стандартный ввод, стандартный вывод, стандартную ошибку в «/ dev / null»
Теперь мы используем daemon (), чтобы переписать программу прямо сейчас:
Результат такой же, как и раньше, только root может преуспеть, обычные пользователи не могут видеть сообщение об ошибке при выполнении
Теперь позвольте daemon (0,1), только не закрывайте стандартные результаты ввода и вывода:
Вы можете увидеть сообщение об ошибке
Теперь давайте daemon (1,0), он не перенаправлен, результат выглядит следующим образом:
На этот раз обычный пользователь преуспел, думая, что он не переключился в каталог / и имеет разрешения
Фактически, мы можем использовать daemon () по умолчанию, который мы только что создали, для создания программы процесса демона:
Код выглядит следующим образом:
Короче говоря, кроме этих специальностей, процесс-демон практически не отличается от обычного процесса. Поэтому написание демона фактически превращает обычный процесс в демон в соответствии с характеристиками демона, описанными выше. Если у вас есть более глубокое понимание процесса, его легче понять и запрограммировать.
(2) Вызовите fork, а затем завершите родительский процесс (выход). if(pid=fork()) exit(0);
(3) Вызовите setsid для создания нового сеанса и выхода из управляющего терминала и группы процессов. Роль функции setsid: используется для создания нового разговора и выступает в качестве лидера группы разговоров.
Вызов setsid имеет три функции: (a) позволить процессу избавиться от исходного управления сеансом, (b) позволить процессу избавиться от исходного управления группой процессов, (c) позволить процессу избавиться от исходного управления терминалом управления setsid()
Цель использования функции setsid: поскольку первым шагом создания процесса-демона является вызов функции fork для создания дочернего процесса, а затем выход из родительского процесса. Когда вызывается функция fork, дочерний процесс копирует период сеанса, группу процессов, управляющий терминал и т. Д. Родительского процесса. Хотя родительский процесс завершается, период сеанса, группа процессов, управляющий терминал и т. Д. Не изменились, поэтому это не так Независимость открылась в смысле. После использования функции setsid процесс может быть полностью независимым, чтобы избавиться от контроля над другими процессами.
(4) Измените текущий рабочий каталог на корневой каталог. #define NOFILE 256 for(i=0;i
(5) Закройте файловые дескрипторы, которые больше не нужны. Это приводит к тому, что демон больше не содержит определенные файловые дескрипторы, унаследованные от его родительского процесса (родительский процесс может быть процессом оболочки или каким-либо другим процессом).
(6) Некоторые демоны открывают / dev / null, чтобы иметь файловые дескрипторы 0, 1 и 2, так что любая библиотечная процедура, которая пытается прочитать стандартный ввод, записать стандартный вывод и стандартную ошибку, не будет иметь никакого эффекта. Поскольку демон не связан с терминальным устройством, его выходные данные не могут быть отображены на терминальном устройстве, и некуда принимать входные данные от интерактивных пользователей.
Linux демон на PHP5
Доброго времени суток, сегодня я буду описывать довольно забавную задачку, из области мало связанной напрямую с web-программированием, а точнее создание демона на PHP. Понятное дело что первым вопросом будет: «А зачем это надо?» Ну что ж, будем разбираться последовательно.
Собственно о постановке задачи. В процессе работы над проектом появилась необходимость интеграции со сторонним комплексом программ. Единственный способ связи с программулиной — общение по средствам его собственного протокола через сетевой порт, ждать наступления события, разобрать ответ, обработать, сохранить в базу. Казалось бы ничего сложно, написать скриптик с бесконечным циклом, внутри которого бы происходила вся необходимая магия и вуаля! В самом начале я рассуждал примерно так же, но вскоре выяснилось что данный подход имеет существенный недостаток, один из которых это некорректные данные, появляющиеся в момент смерти скрипта. Сервер перезагружается и в базе остаются данные, которые не успели ни обработать, ни удалить. Неприятно, очень неприятно.
Ну что ж, давайте разбираться, у нас есть классический LAMP на CentOS, сторонняя софтина и сильное желание не прикручивать какие-нибудь другие инструменты или уж «боже упаси программировать на C». Я посчитал что было бы совсем не плохо если исходный скрипт можно было бы научить распознавать сигналы операционный системы с тем чтобы он завершал свою работу корректно. Для тех кто не знает, в общих чертах, Linux управляет процессами с помощью сигналов, которые говорят процессу как он должен себя вести. При получении такого сигнала процесс должен изменить своё поведение или не делать ничего, если это не требуется для его работы. Лично для меня наиболее интересен сигнал SIGTERM. Этот сигнал говорит о том что процесс должен завершить свою работу. Список всех существующих сигналов можно посмотреть тут:
Сигналы UNIX
Так же имеется и другая особенность, каждый процесс в Linux так или иначе связан с терминалом откуда он был запущен и от него же наследует потоки вводы/вывода, по этому как только вы закроете терминал, в котором запустили скрипт он тут же завершит своё выполнение. Для того чтобы избежать такой ситуации нужно создать дочерний процесс, сделать его основным, прикончить родителя и отвязать оставшийся процесс от ввода/вывода терминала, в котором он был запущен. Согласен, звучит сложно, запутанно и не понятно, но на практике всё значительно проще чем выглядит.
Что нам нужно для работы? В принципе не так много, собственно сам PHP, в моём случае этот PHP5.6 и несколько расширений:
Как было сказано выше, для начала работы нашего демона, в соответствии с правилами работы подобных программ в Linux, его нужно отвязать от терминала, в котором его запустили для этого нужно воспользоваться функцией pcntl_fork(), она создаёт дочернюю копию текущего процесса и возвращает его числовой id в случае успеха. Ну и конечно прикончить родительский процесс.
Таким образом, операционная система будет знать что мы способны определять своё поведение и поместит pid нашего процесса в очередь для получения системных сигналов.
Теперь нас ждёт самое интересное — нужно определить как именно мы будем работать и взаимодействовать с операционной системой. Я решил вынести этот функционал в отдельный класс, на тот случай если этот код ещё понадобится. Приступим, для начала необходимо определиться что что класс должен уметь делать.
Получать и обрабатывать сигналы операционной системы;
Уметь понимать запущен ли демон или нет;
Запускать задачу необходимую для демонизации;
Знать когда нужно остановиться;
Для реализации этих задач стоит разобрать функции, которые нам пригодятся. Функция pcntl_signal(), нужна для того чтобы назначить функцию обработчик для сигнала. Принимает в качестве аргументов: сигнал, для которого назначается обработчик и функцию или метод класса отвечающего за обработку сигнала. Функция getmypid(), которая возвращает pid текущего процесса. Ну и наконец функция posix_kill(), отправляющая сигнал указанному процессу, принимает два аргумента: pid процесса которому нужно отправить сигнал и собственно сам сигнал, который нужно отправить.
Для того чтоб контролировать состояние собственного процесса нам понадобится флаг, который будет определять пора завершаться процессу или нет. Так же имеется некоторая тонкость, для того чтобы сэкономить ресурсы процессора, необходимо делать паузы, в течении которых приложение будет просто ждать следующей итерации цикла, тем самым не нагружая систему постоянными запросами. Необходимо определить эти параметры как поля класса.
Как видите метод принимает в качестве аргумента сигнал, который ему отправляется и в зависимости от того какой сигнал отправлен демону производит те или иные действия.
Теперь нам нужно точно узнать запущен ли наш демон или нет. Как бы так нам это сделать, ведь демон может быть запущен из разных терминалом или несколько раз подряд. Если несколько экземпляров одного и того же скрипта будут пытаться одновременно получить доступ к одним и тем же ресурсам, думаю это будет крайне неприятно. Чтобы избежать такой ситуации, мы можем воспользоваться старым как мир способом, в ходе выполнения программы создать файл в определённом месте с записанным туда pid процесса программы и удалять его каждый раз когда наше приложение закрывается. Таким образом проверяя на существование этот файл мы сможем знать есть ли запущенные копии нашего приложения. Для решения этой задачи определим метод нашего класса.
Здесь мы проверяем все возможные варианты событий, существует ли файл, если да то каким процессом создан, проверяем существует ли такой процесс, если процесс создавший файл не существует, так как процесс завершился неожиданно, пробуем удалить файл.
Самое время подумать, а как же мы будем проделывать собственно те самые операции, ради которых всё и задумывалось? Вариантов реализации тут много. В моём случае нужно было ждать результатов от сторонней службы, без этих данных сам процесс был бесполезен и никаких действий над уже имеющимися данными или ресурсами не производил, поэтому я реализовал всю обработку в функции, которая получала или не получала от сторонней службы данные. Если данных не было, функцию следовало вызывать до тех пор пока они не появятся. Таким образом написанный мною метод класса, реализующий полезную нагрузку зависел от двух параметров: внутреннее состояние демона и результаты работы функции обрабатывающей данные от сторонней службы.
Таким образом у меня получилось два условно бесконечных цикла, внутренний, который ожидает пока функция выполнится и внешний, который ожидает пока изменится состояние демона. Никто не говорит что моя реализация самая правильная, реализацию метода можно переопределять как удобно, не забывая следить за тем пора ли завершать процесс или нет.
Теперь наступает кульминационный момент, на нужно всё это связать вместе и запустить, думаю самое время написать конструктор для нашего класса.
Проверяем с помощью файла запущен ли процесс или нет, если запущен то выводим соответствующее предупреждение, устанавливаем задержку, назначаем обработчики сигналов (в данном случае только один), создаём файл и записываем туда свой pid, чтобы знать другие копии процесса знали что мы уже работаем. С классом мы закончили.
Теперь возвращаемся к написанию самого скрипта демона. Мы остановились на том что закончили все приготовления для запуска демона.
Мы подключаем все библиотеки, которые нам нужны, в том числе и файл с нашим классом Daemon.php, описываем функцию, которая будет выполнять полезную нагрузку, создаём экземпляр класса Daemon с нужными нам параметрами, отвязываем стандартный ввод/вывод от текущего терминала и перенаправляем их в /dev/null (если мы сделали бы это раньше, то рисковали бы не увидеть сообщения об ошибках в процессе выполнения скрипта), передаём методу run класса Daemon, нашу функцию, которая будет выполняться демоном.
На этом всё. Наш демон работает и прекрасно общается с ОС. Все хорошего и удачи.