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

0

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

Теги:
publish-subscribe
zeromq

1 ответ

1

Проблема связана с симптом "медленного столяра" 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.

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню