ratchetphp / Ratchet

Asynchronous WebSocket server
http://socketo.me
MIT License
6.28k stars 743 forks source link

send() not being received? #710

Closed JoshIPT closed 5 years ago

JoshIPT commented 5 years ago

Basic app written based on the helloworld example, with modifications. The server seems to listen and receive messages just fine, but send() is never received by the browser?

This is my server-side code:

<?php
    require dirname(__DIR__) . '/vendor/autoload.php';
    require_once("/var/www/shared/PEAR2/Autoload.php");
    use PEAR2\Net\RouterOS;
    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;
    use Ratchet\Server\IoServer;
    use Ratchet\Http\HttpServer;
    use Ratchet\WebSocket\WsServer;

    $clientArray = array();

    class LiveStream implements MessageComponentInterface {
        public function __construct() {
        }

        public function onOpen(ConnectionInterface $conn) {
            global $clientArray;
            $clientArray[$conn->resourceId] = $conn;
            print "New client connected\n";
        }

        public function onMessage(ConnectionInterface $from, $msg) {
            print "Got message: {$msg}\n";
            $json = json_decode($msg, true);
            if ($json == NULL) {
                print "Malformed request. Disconnecting.\n";
                $from->close();
            }
            else {
                streamNTD($from->resourceId, $json["ip"], $json["cmd"]);
            }
        }

        public function onClose(ConnectionInterface $conn) {
            global $clientArray;
            print "Client disconnected.\n";
            $clientArray[$conn->resourceId] = NULL;
        }

        public function onError(ConnectionInterface $conn, \Exception $e) {
        }
    }

    class streamWorker {
        private $clientid;
        private $ip;
        private $cmd;
        public function __construct($clientid, $ip, $cmd) {
            $this->clientid = $clientid;
            $this->ip = $ip;
            $this->cmd = $cmd;
        }
        public function run() {
            $tik = new RouterOS\Client($this->ip, "admin", "********");
            $req = new RouterOS\Request('/interface monitor-traffic');
            $req->setArgument("interface", "ether1");

            $req->setTag($this->clientid);
            $tik->sendAsync($req, 'writeEthStats');
            $tik->loop();
        }
    }

    function writeEthStats($response) {
        global $clientArray;
        if ($response->getType() === RouterOS\Response::TYPE_DATA) {
            $spd = array(
                        "rx" => $response->getProperty("rx-bits-per-second"),
                        "tx" => $response->getProperty("tx-bits-per-second"));
            $msg = json_encode($spd, JSON_FORCE_OBJECT);
            print "Sending: {$msg}\n";
            $ret = $clientArray[$response->getTag()]->send($msg);
        }
    }

    function streamNTD($clientid, $ip, $cmd) {
        global $clientArray;
        $th = new streamWorker($clientid, $ip, $cmd);
        try {
            $th->run();
        } catch (Exception $x) {
            var_dump($x);
        }
    }

    $server = IoServer::factory(
        new HttpServer(
            new WsServer(
                new LiveStream()
            )
        ),
        8066
    );

    $server->run();
?>

Client side code is just as the sample on the documentation:

var conn = new WebSocket('ws://whmcs.iptelco.com.au:8066/');
conn.onopen = function(e) {
    console.log("Connection established!");
};

conn.onmessage = function(e) {
    console.log(e);
};

And then sending a message via: conn.send('{"ip": "10.100.12.194", "cmd": "meep"}');

Message is received. JSON decoded. streamNTD is initialised, does what it needs to do and calls send() with the JSON to send back but this message is never received. I have done a var_dump() on the send call and got a valid object back.

Ideas?

JoshIPT commented 5 years ago

The output on the server side shows:

New client connected
Got message: {"ip": "10.100.12.194", "cmd": "meep"}
Sending: {"rx":"10584","tx":"6744"}
Sending: {"rx":"3504","tx":"7136"}
Sending: {"rx":"3504","tx":"7136"}
.........

None of those messages are received.

mbonneau commented 5 years ago

$tik->loop() is a blocking call. Script execution will hang there and remain inside the RouterOS client. Ratchet will not be able to send or process messages as it relies on its own React event loop.

I am not sure if there are ways to make them compatible with each other. One possibility is to run $tik->loop() periodically from the React loop with a timeout specified.