Как установить тайм-аут на fopen с именованными каналами

Я пытаюсь сделать некоторые IPC в PHP, используя именованные каналы. У меня есть именованный канал, созданный с помощью

$pipePath = __DIR__ . '/pipe';
posix_mkfifo($pipePath, 0600);

Есть еще один процесс, который должен записать в этот канал после завершения вычислений. Я могу дождаться его окончания и прочитать результат примерно так:

$result = file_get_contents($pipePath);

или более многословный

$in = fopen($pipePath, 'r');
$result = fread($in, 8192);
fclose($in);

(Я упростил второй подход; в реальном коде я бы проверил на ошибки, запустите fread в цикле, если результат> 8192 байт и т. д.)

Однако пока другой процесс должен В завершение, я не верю, что это будет успешным, поэтому я хочу иметь тайм-аут при попытке прочитать результат. После некоторого ожидания я хочу сдаться и сообщить об ошибке, сообщив, что произошел сбой, и т. Д. При двух указанных подходах код PHP будет зависать вечно (или для очень давно) жду что нибудь написать в трубу. В частности, file_get_contents а также fread будет висеть

Единственное решение, которое мне удалось найти, это что-то вроде этого:

$timeout = 10; //seconds
for ($i = 0; $i < $timeout; $i++) {
$in = @fopen($pipePath, 'rn');
if ($in) break;
sleep(1);
}
if (!$in) {
throw new RuntimeException("The other process did not finish in the allotted time");
}
$result = fread($in, 8192);
fclose($in);

Это использует недокументированное 'n' флаг для fopen как показано в одном из комментариев на этот вопрос. Это вызывает fopen вызов немедленно прервется, если он заблокируется.

Однако мне не нравится это решение по двум причинам:

  1. Это делает ненужную работу, проверяя трубу каждую секунду.
  2. Если вычисление в другом процессе занимает 1,01 секунды, это займет целых 2 секунды, чтобы получить результат. Для некоторых вещей, которые я хочу сделать, достаточно потраченного времени, чтобы попытаться решить проблему.

когда fopen вызывается по URL, у меня есть возможность добавить параметр контекста, который указывает значение времени ожидания. Тем не менее, это, похоже, не работает для этого и не устанавливает время ожидания сокета по умолчанию.

Есть ли лучший способ сделать это с трубами? Если нет, я мог бы рассмотреть возможность перехода на сокеты Unix, но их не так просто поддерживать в другом процессе, поэтому я бы не стал этого делать.

(К вашему сведению, меня интересует только Linux; нет необходимости иметь что-то, что работает на Windows или что-то еще, в случае, если это имеет значение.)

5

Решение

Я нашел один способ сделать это …

Во-первых, я не знал о n флаг, это была очень полезная информация!

Тем не менее, это не совсем верно, что функция не работает, если она будет блокировать. Он по-прежнему возвращает дескриптор файла. Мы можем использовать дескриптор файла и передать его stream_select функция ожидания, когда данные станут доступны.

Что-то вроде этого:

$f=fopen("my.fifo","rn");
$r=array($f);
$w=array();
$x=array();
stream_select($r,$w,$x,10);

Этот код ждет 10 секунд, пока кто-то еще не напишет на другом конце fifo.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]