У меня есть этот простой код для палитра/подстановки ZeroMQ в PHP, и странная часть заключается в том, что он работает для одиночных (1x) веб-запросов, когда я комментирую while (true) {//code}, он не работает веб-клиент не получает единственный запрос, но когда publisher-> send() вызывается внутри цикла, веб-клиент обычно получает все сообщение.
ZeroMQ PHP Publisher
<?php
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache'); // recommended to prevent caching of event dat
header("Connection: keep-alive");
$port=8899;
// Prepare our context and publisher
$context = new ZMQContext();
$publisher = $context->getSocket(ZMQ::SOCKET_PUB);
$publisher->bind("tcp://*:".$port);
echo "Running..Serving test data on TCP port $port every 1 s \n <hr>";
while (true) { //doesn't work when this line is commented out
$count++;
$json=json_encode(array($count, PHP_RELEASE_VERSION, PHP_OS , $_SERVER['PHP_SELF'], Date("h:i:s m-d-Y") ) );
$publisher->send( $json);
sleep(1);
echo "+";
ob_flush();
flush(); //send out to browser
}
?>
Подписчик ZeroMQ PHP
<?php
header('Cache-Control: no-cache'); // recommended to prevent caching of event dat
header("Connection: keep-alive");
$context = new ZMQContext();
$subscriber = $context->getSocket(ZMQ::SOCKET_SUB);
$subscriber->setSockOpt(ZMQ::SOCKOPT_SUBSCRIBE, '');
$port=8899;
$subscriber->connect('tcp://localhost:'.$port);
while(true) {
echo "<br>Waiting for message " ;
$string = $subscriber->recv();
echo "<br>Received ".$string ;
ob_flush();
flush();
}
?>
Я подозреваю, что это связано с тем, когда скрипт PHP заканчивается, сообщение ZeroMQ никогда не отправляется и не закрывается для отдельных запросов.
Проблема связана с симптом "медленного столяра" ZeroMQ в пабе/подсистеме, как это обсуждалось здесь в их руководстве:
Еще важнее знать о сокетах PUB-SUB: вы точно не знаете, когда абонент начинает получать сообщения. Даже если вы запустите подписчика, подождите некоторое время, а затем запустите издателя, абонент всегда пропустит первые сообщения, которые отправляет издатель. Это связано с тем, что, когда абонент подключается к издателю (что принимает небольшое, но ненулевое время), издатель может уже отправлять сообщения.
Проблема в вышеприведенном коде находится на скрипте Publisher ZeroMQ PHP Publisher. В основном из-за времени, которое требуется ZeroMQ для настройки Socket и выполнения этой подготовительной работы (небольшое, но ненулевое время), существует небольшая задержка, когда издатель сначала устанавливает MQ.
Сложная часть заключается в том, что он возвращается сразу после вызова:
// Prepare our context and publisher
$context = new ZMQContext();
$publisher = $context->getSocket(ZMQ::SOCKET_PUB);
$publisher->bind("tcp://*:".$port); //returns immediately BUT NOT REALLY ready
то, конечно, остальная часть выше PHP проходит через менее 10 мс, поэтому, когда вы выдаете фактическую команду отправки, MQ еще не настроен, и это исходное сообщение теряется.
$publisher->send( $json); //send the message but MQ not REALLY setup just yet.
Это, конечно, вызывает эту путаницу, поскольку в программировании вы ожидаете, что когда функция (например, $publisher-> bind) вернется успешно, она выполнила задание, но на самом деле она не...
Простое решение - использовать небольшую задержку (вам нужно сыграть со значением задержки) сразу после привязки, чтобы дать ZeroMQ возможность завершить свою работу. Теперь этот подход не самый элегантный, поскольку размер задержки может варьироваться в зависимости от машины и т.д., И руководство по ZeroMq расскажет вам об этом.
Люди в ZeroMQ рекомендуют использовать более изощренный подход, поддерживающий отслеживание подписчиков и имеющий обратный канал, с которым подписчики могут общаться с издателем, когда они присоединились.
Для моих целей этот подход является излишним, поэтому приведенная ниже команда работает нормально, просто дайте значению времени для простоя.
$port=8899;
// Prepare our context and publisher
$context = new ZMQContext();
$publisher = $context->getSocket(ZMQ::SOCKET_PUB);
$publisher->bind("tcp://*:".$port);
usleep(250000); //wait 0.25 secs enougth for ZeroMQ to build the socket.
Это сработало для меня...