Реализация fork на shell-скриптах?

Автор epros, 24 ноября 2013, 23:27:55

« назад - далее »

0 Пользователи и 1 гость просматривают эту тему.

epros

Мне тут потребовалось запустить демон из скрипта php (модуль Apache). Тупые методы типа:

`command &`не срабатывают: Если command успевает запуститься до завершения скрипта, то скрипт просто не хочет завершаться - вероятно, ждёт завершения дочернего процесса, не глядя на то, что тот запущен в фоне.

К моему сожалению, также выяснилось, что модуль управления потоками (pcntl) из php, скомпилированного как модуль Apache, недоступен. В частности, нет функции pcntl_fork(). Однако в консольной версии php это всё есть. Поэтому я наваял примерно такой скрипт:

Файл 'start_daemon':

#!/usr/bin/php5
<?php
function shutdown($child_pid) {
   
posix_kill($child_pidSIGKILL);
}

$child_pid pcntl_fork(); // Разветвляем процесс

if ($child_pid) { // Это ветка родительского процесса

    
register_shutdown_function('shutdown'$child_pid);
      
// Функция shutdown будет вызвана при завершении родительского процесса
      // чтобы убить дочерний процесс после того, как он запустит демон
    
sleep(1);
      
// Даём дочернему процессу секунду на запуск демона
    
exit;
}
      
// А эта ветка выполняется только в дочернем процессе.

`setsid command &`;
      
// Команда setsid отвязывает демон command от родителя:
      // дочернего процесса php, который его запустил
?>
который можно запустить как из консоли, так и командой из того php, который модуль Apache.

Например так:

`start_daemon`;


А можно это как-то написать не в форме php-скрипта, а обычным bash-скриптом? Что-то я не нашёл никакой команды, аналогичной pcntl_fork().

yura_n

Если я правильно понимаю, вы хотите запустить из Bash процесс таким образом, чтобы он отвязался от текущего окружения. Самое смешное:

#!/bin/bash
start_daemon &

Новый скрипт будет запущен уже в форке. Bash форкует окружение по умолчанию.

epros

#2
Цитата: yura_n от 25 ноября 2013, 01:12:15
Если я правильно понимаю, вы хотите запустить из Bash процесс таким образом, чтобы он отвязался от текущего окружения. Самое смешное:

#!/bin/bash
start_daemon &

Новый скрипт будет запущен уже в форке. Bash форкует окружение по умолчанию.
Хм, я не понял идеи. start_daemon - это файл с php-скриптом, который я хотел переписать. Если Вы имели в виду:

Файл start_daemon:

#!/bin/bash
command &
(command - это тот демон, которого нужно запустить), то это, конечно, будет работать из командной строки, но при попытке запустить этот файл из php-скрипта, который Apache запускает по запросу от веб-клиента, php-скрипт не завершается. Т.е. клиенту приходится нажимать в браузере кнопку "стоп".

yura_n

#3
Цитата: epros от 25 ноября 2013, 12:51:12но при попытке запустить этот файл из php-скрипта, который Apache запускает по запросу от веб-клиента, php-скрипт не завершается.
Вероятно, это заморочка PHP интерпретатора. Он хочет вывести результат выполнения внешней программы на стандартный вывод и ждет пока она не выполнится. Вам возможно нужно перенаправить стандартный вывод функции PHP, которая запускает внешнюю программу.

epros

#4
Цитата: yura_n от 25 ноября 2013, 17:46:50Он хочет вывести результат выполнения внешней программы на стандартный вывод и ждет пока она не выполнится. Вам возможно нужно перенаправить стандартный вывод функции PHP, которая запускает внешнюю программу.
Непонятно, что перенаправлять. Если я просто запускаю демон строкой:

`start_daemon`;, то php, по идее, никаких выводов от этой команды ждать не должен. Про крайней мере, если start_daemon написан на php (как описано выше), никаких проблем не возникает - скрипт завершается. Но bash-скрипт почему-то ведёт себя иначе. Кстати, отвязка от родительского процесса командой setsid тоже не спасает. Т.е. вот такой вариант файла start_daemon тоже корректно не отрабатывает:

Файл start_daemon:

#!/bin/bash
setsid command &

yura_n

#5
Цитата: epros от 26 ноября 2013, 14:49:09Непонятно, что перенаправлять.
Из php вы можете сделать что-то вроде:

<?php
exec
('/path_to_file/test.sh > /dev/null &');
?>


Или так:

<?php
exec
('/path_to_file/test.sh > /path_to_file/file &');
?>


Тогда PHP интерпретатор не будет ждать завершения программы.