По умолчанию stream_get_contents
ждет и слушает 60 секунд. если у меня несколько потоков и вы хотите их постоянно слушать.
Внутри foreach, если я слушаю один поток, я не могу слушать другие.
Каково решение для непрерывного прослушивания и записи потока для всех потоков?
while(true){ //$streamArray is an array of streams obtained by stream_socket_client("tcp://..); foreach($streamArray as $stream){ fputs($stream,$command); stream_get_contents($stream); // and update file/DB (Blocking call) } }
вwhile(true){ //$streamArray is an array of streams obtained by stream_socket_client("tcp://..); foreach($streamArray as $stream){ fputs($stream,$command); stream_get_contents($stream); // and update file/DB (Blocking call) } }
Примечание. Для каждого потока я уже выполнил stream_set_blocking( $stream , true );
Обновить:
Мое требование – слушать все потоки в течение некоторого времени, скажем, 30 монетных дворов. в то же время я не могу слушать 2 потока. если у меня 5 потоков, мой код – это просто time division multiplexing
, из 30 монетных дворов каждый отдельный поток будет записан только для 6 монетных дворов
У меня есть одно решение, которое делает запрос AJAX для отдельного потока и записывается независимо. Конечно, я не хочу делать этот множественный метод вызова AJAX, так как это приведет к большему количеству кода, а также к более высокому процессору.
с stream_set_blocking($resource, true)
вы начинаете чтение потоков (ов) синхронно , что означает, что каждый вызов fread()
ожидает, пока не будут прочитаны данные. Затем вы вызываете stream_get_contents()
, который читает из потока блокировки, пока не достигнет EOF (закрыт). В результате вы читаете один поток за другим, а не «одновременно».
Чтение потоков таким образом является общим и самым простым для кодирования, но когда вы хотите обрабатывать несколько потоков одновременно, вы должны самостоятельно обрабатывать буферы, время и «конец потока». С вашим текущим кодом эта часть абстрагируется от вас через блокирующие потоки и stream_get_contents()
.
Чтобы читать несколько потоков одновременно, вы должны переписать свой код, чтобы читать потоки (а) синхронно .
Неисследованный псевдо пример:
// $streamArray is an array of streams obtained by stream_socket_client(".."); $buffers = array(); $num_streams = 0; foreach($streamArray as $stream) { // set streams non-blocking for asynchroneous reading stream_set_blocking($stream, false); // write command to all streams - multiplexing fputs($stream, $command); // initialize buffers $buffers[$stream] = ''; $num_streams++; } while($num_streams) { // use stream_select() to wait for new data and not use CPU at 100%. // note that the stream arrays are passed by reference and are modified // by stream_select() to reflect which streams are modified / have a // new event. Because of this we use a copy of the original stream array. // also note that due to a limitation in ZE you can not pass NULL directly // for more info: read the manual $no_stream = NULL; $select_read = $streamArray; stream_select($select_read, $no_stream, $no_stream, null); // if there is new data, read into the buffer(s) foreach($select_read as $stream) { $buffers[$stream] .= fread($stream, 4096); // check if the stream reached end if (feof($stream)) { $key = array_search($stream, $streamArray); // close stream properly $num_streams--; fclose($stream); // remove stream from array of open streams unset($streamArray[$key]); } } } // do something with your buffers - our use them inside the while() loop already print_r($buffers);
с// $streamArray is an array of streams obtained by stream_socket_client(".."); $buffers = array(); $num_streams = 0; foreach($streamArray as $stream) { // set streams non-blocking for asynchroneous reading stream_set_blocking($stream, false); // write command to all streams - multiplexing fputs($stream, $command); // initialize buffers $buffers[$stream] = ''; $num_streams++; } while($num_streams) { // use stream_select() to wait for new data and not use CPU at 100%. // note that the stream arrays are passed by reference and are modified // by stream_select() to reflect which streams are modified / have a // new event. Because of this we use a copy of the original stream array. // also note that due to a limitation in ZE you can not pass NULL directly // for more info: read the manual $no_stream = NULL; $select_read = $streamArray; stream_select($select_read, $no_stream, $no_stream, null); // if there is new data, read into the buffer(s) foreach($select_read as $stream) { $buffers[$stream] .= fread($stream, 4096); // check if the stream reached end if (feof($stream)) { $key = array_search($stream, $streamArray); // close stream properly $num_streams--; fclose($stream); // remove stream from array of open streams unset($streamArray[$key]); } } } // do something with your buffers - our use them inside the while() loop already print_r($buffers);
PHP работает как один процесс на сервере. «Лучший» способ сделать что-то подобное – это создать поток для каждого потока. Каждый поток будет иметь один поток для прослушивания. Многопоточность автоматически использует несколько процессоров и позволяет им работать параллельно.
К сожалению, PHP не позволяет создавать потоки. Однако есть несколько вариантов для работы (обратите внимание: этот вопрос может принести вам пользу).
Вариант 1: клонировать процесс
PHP позволяет вам клонировать текущий процесс с помощью таких функций, как pcntl_fork . В принципе, вы можете создать копию текущего PHP-процесса, и этот процесс вступит в силу и начнет работать. Просто сделайте это для каждого потока, который нужно прослушать. Усложнение будет гарантировать, что каждый процесс прослушивает правильный поток. ( Подсказка : иметь список потоков и использовать флаг для следующего потока в списке. Затем сделать fork [клонировать процесс]. Детский процесс начнет прослушивать этот поток. Но в родительском флажке обновите флаг к следующему потоку в списке и создать другого ребенка, и так далее …)
Вариант 2: несколько экземпляров PHP
Вы можете использовать Cronjob, несколько вызовов или какую-либо другую услугу (даже вызов командной строки) для вызова каждого скрипта PHP или передать параметр сценарию, чтобы определить, какой поток прослушать. Это будет запускать каждый скрипт / файл PHP параллельно и достигнет того, чего вы хотите.
Вариант 3: Не используйте PHP
PHP не был технически построен для подобных вещей, и это, вероятно, можно было бы легко достичь на C, C ++ или Java. Вы должны подумать о своей настройке.
Вариант 4. Создание модуля PHP или Apache
Вы можете написать модуль в C для PHP или Apache, а затем использовать свои вызовы функций из PHP. Это, вероятно, будет довольно сложно, и я не рекомендую его.
В целом, я рекомендую переосмыслить вашу настройку и не использовать PHP. Но если вы ограничены PHP, то несколько вызовов AJAX – это путь.
Каково решение для непрерывного прослушивания и записи потока для всех потоков?
Эта проблема долгое время беспокоила программистов. Книга под названием « Сетевое программирование UNIX», написанная У. Ричардом Стивенсом, была бы хорошей отправной точкой, если вы после достойного решения своей проблемы.