ZeroMQ Pub / sub с PHP не работает на одном веб-соединении, но работает с циклом

У меня есть этот простой код для установки паба / подзаголовка 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 никогда не отправляется и не закрывается для отдельных запросов.

0

Решение

Проблема связана с симптомом «медленного соединения» ZeroMQ в ситуации паб / суб, как обсуждается здесь в их руководстве:

Есть еще одна важная вещь, которую нужно знать о разъемах PUB-SUB: вы
не знаю точно, когда подписчик начинает получать сообщения. Четное
если вы запускаете подписчика, подождите некоторое время, а затем запустите издателя,
подписчик всегда будет пропускать первые сообщения, которые издатель
посылает.
Это связано с тем, что подписчик подключается к издателю.
(то, что занимает небольшое, но ненулевое время), издатель может
уже отправлять сообщения.

Проблема в вышеприведенном коде связана со скриптом 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 рекомендуют использовать более сложный подход для отслеживания подписчиков и наличия обратного канала, который присоединяющиеся подписчики могут общаться с издателем, когда они присоединились.

Для моих целей такой подход является излишним, поэтому приведенная ниже команда работает нормально, просто дайте значению usleep достаточно времени ..

  $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.

Это сработало для меня …

1

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

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

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