В-четвертых, концепции, относящиеся к сеансу: группа процессов, группа процессов переднего плана, группа фоновых процессов, сеанс, терминал управления
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 в терминале
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); // Завершаем первый дочерний процесс, и второй дочерний процесс продолжается (второй дочерний процесс больше не является лидером сеанса)
Демоны, как правило, начинают работать при запуске системы, и если их не принудительно завершить, в противном случае продолжайте работу, пока система не будет выключена. Демоны часто запускаются с привилегиями суперпользователя (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 () для создания процесса-демона, прототип функции:
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, так что любая библиотечная процедура, которая пытается прочитать стандартный ввод, записать стандартный вывод и стандартную ошибку, не будет иметь никакого эффекта. Поскольку демон не связан с терминальным устройством, его выходные данные не могут быть отображены на терминальном устройстве, и некуда принимать входные данные от интерактивных пользователей.
Доброго времени суток, сегодня я буду описывать довольно забавную задачку, из области мало связанной напрямую с 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, нашу функцию, которая будет выполняться демоном.
На этом всё. Наш демон работает и прекрасно общается с ОС. Все хорошего и удачи.
Теперь вы знаете какие однокоренные слова подходят к слову Как написать демона linux, а так же какой у него корень, приставка, суффикс и окончание. Вы можете дополнить список однокоренных слов к слову "Как написать демона linux", предложив свой вариант в комментариях ниже, а также выразить свое несогласие проведенным с морфемным разбором.