Search code examples
phpzeromqreactphp

ZMQ REP REQ - Send Receive not working


I have my websocket server up and running, and for my own use I want to get back a list of the connected when I execute a static PHP script.

My PHP script pull.php:

$context = new ZMQContext();
$socket = $context->getSocket(ZMQ::SOCKET_REQ);
$socket->connect("tcp://localhost:5552");

$socket->send('data');

$test = $socket->recv();

var_dump($test);

Then on my server script:

<?php
require './vendor/autoload.php';

$loop   = React\EventLoop\Factory::create();
$pusher = new MyApp\Pusher;

$context = new React\ZMQ\Context($loop);

$pull = $context->getSocket(ZMQ::SOCKET_REP);
$pull->bind('tcp://127.0.0.1:5552');
$pull->on('message', array($pusher, 'onPull'));
$pull->recv();
$pull->send('response');

$webSock = new React\Socket\Server($loop);
$webSock->listen(8080, '0.0.0.0');
$webServer = new Ratchet\Server\IoServer(
    new Ratchet\Http\HttpServer(
        new Ratchet\WebSocket\WsServer(
            $pusher
        )
    ),
    $webSock
);

$loop->run();

So when my server script is running, I then run pull.php. This works, and sends me back the response text which I var_dump out. However, if I then go and reload my pull.php script, it just hangs. I've no idea why, I am assuming here that somewhere down the line it's not telling the other party that it has received the data and thus can't send another request.

Also, my $pull->on('message', array($pusher, 'onPull')); currently sends the data into my onPull() method in my Pusher class. At the moment I just return nothing, but if I return some data how do I get this back to the requester?


Solution

  • You should add the code from your Pusher class so we can see the onPull method... this looks like it is still mostly your push/pull code rather than req/rep, which may throw some things off (for other's reference, his first question which included some indication of his use of push/pull, is here)

    However, I think I see the issue (comments in-line):

    <?php
    require './vendor/autoload.php';
    
    $loop   = React\EventLoop\Factory::create();
    /*******************
    first red flag - you use your Pusher class, which presumably is set up
    to handle a push/pull scenario rather than a req/rep scenario
    *******************/
    $pusher = new MyApp\Pusher;
    
    $context = new React\ZMQ\Context($loop);
    
    /*******************
    Why are you naming a REP socket $pull?  Change your code appropriately when you
    copy/paste, it will help issues to stand out more
    *******************/
    $pull = $context->getSocket(ZMQ::SOCKET_REP);
    $pull->bind('tcp://127.0.0.1:5552');
    /*******************
    second red flag - you set up a message handler that deals with a message event
    and then you go on to manually call recv and send - this is probably your issue.
    recv() will block until it receives your first request from the client, then it
    will send your 'response', but this will only ever handle the very first message    
    *******************/
    $pull->on('message', array($pusher, 'onPull'));
    $pull->recv();
    $pull->send('response');
    
    /*******************
    I don't know what this is doing here, since your client is a ZMQ client and not an
    HTTP client
    *******************/
    $webSock = new React\Socket\Server($loop);
    $webSock->listen(8080, '0.0.0.0');
    $webServer = new Ratchet\Server\IoServer(
        new Ratchet\Http\HttpServer(
            new Ratchet\WebSocket\WsServer(
                $pusher
            )
        ),
        $webSock
    );
    
    /*******************
    presumably this loop should handle subsequent messages, but it's either set up
    for push/pull or HTTP, or both, I can't quite tell
    *******************/
    $loop->run();
    

    I don't think you want Ratchet or Websockets at all here, you just want to talk to a ZMQ client, correct? So, pull that code out. What you most likely want instead is to define your on-message handler to handle the request and send a response. Try the following (this is based off of a very little research into React, where I couldn't find a req/rep example, so if this doesn't work then let me know)

    <?php
    require './vendor/autoload.php';
    
    $loop   = React\EventLoop\Factory::create();
    $context = new React\ZMQ\Context($loop);
    
    $rep = $context->getSocket(ZMQ::SOCKET_REP);
    $rep->bind('tcp://127.0.0.1:5552');
    $rep->on('message', function($msg) use ($rep) {
        // the "use ($rep)" syntax is PHP 5.4 or later
        // if you're using an older version of PHP, just use $GLOBAL['rep'] instead
        $rep->send('response');
    });
    
    $loop->run();