Скачиваний:
18
Добавлен:
02.05.2014
Размер:
906.24 Кб
Скачать

13. Каналы и символические ссылки

Вообще-то, каналы и символические ссылки – совершенно разные вещи. Однако у меня есть по крайней мере два веских основания для того, чтобы сгруппировать их описания в одном месте.

●И то и другое сколько-нибудь результативно можно использовать лишь в системах на основе Unix, в других же операционных системах функции либо не реализованы, либо просто не работают.

●Примерно лишь один сценарий на PHP из тысячи может нуждаться в создании и использовании каналов и символических ссылок.

Каналы

Давайте начнем с каналов. Мы уже привыкли, что можем открыть какой-то файл для чтения при помощи fopen(), а затем читать или писать в него данные. Теперь представьте себе немного отвлеченную ситуацию: вы хотите из сценария запустить какуюто внешнюю программу (скажем, утилиту mail для отправки или приема почты). Вам нужен будет механизм, посредством которого вы могли бы передать этой утилите данные (например, E-mail и текст письма), а затем получить результат работы программы. Можно, конечно, заранее сохранить данные для запроса в отдельном временном файле, затем запустить программу, передав ей этот файл в параметрах и направив результат в другой файл, а затем считать его и таким образом решить задачу. Этот способ вполне приемлем (хотя и несколько медлителен), если вы используетеутилиту, которая работает не в режиме диалога (а только читает запрос и возвращает ответ). Однако, если после ответа программы-утилиты ей нужно будет послать какой-то другой запрос, не перезапускаясь, то задача становится на этом уровне неразрешимой. Как раз в такой ситуации и удобно использовать межпроцессные каналы. И вот как это работает.

// Запускаем процесс /bin/ls (параллельно работе сценария) в режиме

// чтения. Эта утилита Unix просто распечатывает содержимое текущего

// каталога, а ключ -l заставляет ее детализировать распечатку.

$fp=popen("/bin/ls -l","r");

// Теперь мы можем работать с $fp как с обычным файловым

// идентификатором. То есть выполнять функции чтения.

for($Lines=array(); !eof($fp);)

$Lines[]=fgets($fp,1000);

// Не забудем также закрыть канал.

pclose($fp);

Теперь более подробно. По команде popen() запускается указанная в первом параметре программа, причем выполняется она параллельно сценарию. Соответственно, управление сразу возвращается на следующую строку, и сценарий не ждет, пока завершится наша утилита (в отличие от функции system ()). Второй параметр задает режим работы: чтение или запись, точно так же, как это делается в функции fopen(). Хочу обратить ваше внимание на то, что каналнельзя открыть в режиме одновременного чтения и записи. Что послужило этому причиной? Ответ на поставленный вопрос в деталях занял бы слишком много места, чтобы поместиться в этой книге, но в двух словах можно сказать так: из-за буферизации ввода-вывода реально возникновение ситуации, когда процесс-родитель будет находиться в режиме ожидания данных от запущенного сына, а сын – будет ждать данные от родителя. Таким образом, возникает состояниевзаимной блокировки: оба процесса оказываются приостановлены. В общем случае эта проблема неразрешима, если у нас нет полного контроля над кодом процесса-сына.

Далее в нашем примере происходит вот что. Стандартный вывод утилиты (тот, который по умолчанию всегда является просто выводом на экран – да простят меня поклонники Unix, но все-таки так будет проще объяснить, не разъясняя, что такое перенаправление ввода-вывода и какую роль оно играет в этой ОС) прикрепляется к идентификатору $fp. Теперь все, что печатает утилита (а в нашем случае она печатает содержимое каталога), может быть прочитано при помощи обычных вызовов файловых функций чтения – fgets(), fread() и т. д. Программа ls не ждет никакого ввода (однако в общем случае это далеко не всегда так), вот почему мы пользуемся только серией вызовов fgets(). После того, как "дело сделано", канал $fp, вообще говоря, нужно закрыть. Если он ранее был открыт в режиме записи, утилите "на том конце" передается, что ввод данных "с клавиатуры" завершен, и она может закончить свою работу. В PHP не существует функций, которые могли бы открывать канал к дочернему процессу в режиме чтения и записи.

169