Send user ID from browser to websocket server while opening connection

我只是一个虾纸丫 提交于 2019-12-18 17:29:44

问题


Before asking this question, I did my best by reading severel questions on SO (tagged Ratchet and dealing with similar issues but to no avail. I even asked a question which received no attention and I therefore deleted it to write another one (that hopefully is more clear).

My final goal is to build a one-to-one private chat application using Ratchet. Everything is working fine except that I can't send message to a specific user.

Every logged in user connects to the websocket server while accessing secured area of website:

$(document).ready(function() { 

    var conn = new WebSocket('ws://localhost:8080');
        conn.onopen = function(e) {
            console.log("Connection established!");

            // Here I need to send the logged in user_id to websocket server
            // and get it in onOpen method so that I can index my array 
            // of connections with user_id instead of
            //$connection->ResourceId, I explain more below

        };

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

});

When a user writes a message in the chat box, the message is sent via AJAX to web server then pushed to Websocket using ZeroMQ. In the controller:

// Persistence of Message(message_id, sender_id, receiver_id, message_text)
                .....

                $context = new \ZMQContext();
                $socket = $context->getSocket(\ZMQ::SOCKET_PUSH, 'my pusher');
                $socket->connect("tcp://localhost:5555");

                $pushData = array(
                       'receiver_id' => $receiver_id,
                       'sender_id'  => $user->getId(),
                       'message'  => $message->getMessageText(),
                    );
                $socket->send(json_encode($pushData));

So at the end, my websocket server is able to know which is the id of receiver using the JSON. But how will he know which is the connection of that user? In other words, I need to store websocket connections in an array that is indexed by the user id.

<?php
namespace RealTime;

use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Wamp\WampServerInterface;

class Pusher implements WampServerInterface, MessageComponentInterface{

    private $clients;

    public function onOpen(ConnectionInterface $conn) {

        $this->clients[$conn->resourceId] = $conn;
        // I need here to get the user_id received from browser while opening connection
    }

    public function onMessageEntry($entry) {
        $entryData = json_decode($entry, true);

        //This is not what I need (It sends to all users in array)
        foreach ($this->clients as $key => $client) {

        $client->send($entryData['message']); 
        }
    }
    public function onMessage(ConnectionInterface $from, $msg) {
        echo $msg; 
    }
}

And the websocket server:

  <?php
        require dirname(__DIR__) . '/vendor/autoload.php';
        use RealTime\Pusher;

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

        $context = new React\ZMQ\Context($loop);
        $pull = $context->getSocket(ZMQ::SOCKET_PULL);
        $pull->bind('tcp://127.0.0.1:5555'); 
        $pull->on('message', array($pusher, 'onMessageEntry'));


        $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(
                    new Ratchet\Wamp\WampServer(
                        $pusher
                    )
                )
            ),
            $webSock
        );
        $loop->run();

        ?>

Questions:

  1. How to send the logged in user_id from client side while opening connection.I need to have the value in websocket server so that I can index my array of clients with it ($client[user_id]=$conn instead of $client[recourceId]=$conn). I tried the javascript function send but I don't know where to receive the sent data (even onMessage is not printing anything).

  2. Why the onMessage method is not executing even MessageComponentInterface implemented (Is it because I have onMessageEntry method + $pull->on('message', array($pusher, 'onMessageEntry')); line of code?

Thank you.


回答1:


I was asked by "whiteletters in blankpapers" to contribute on this subject (sorry for being late).

Actually on my last try, I gave up on PHP WebSocket (it was so complicated to make this work) and started using SocketIO with nodeJS that solved my entire problem and could give me a functionnal simple Chat system.




回答2:


This is what I found and any suggestions to enhance this solution are welcome.

One can use the Ratchet SessionProvider. This will require using one of the Symfony Custom Session handlers as indicated. I use in the following code the PdoSessionHandler.

<?php
    require dirname(__DIR__) . '/vendor/autoload.php';

    use YourDirectory\Pusher;
    use Symfony\Component\HttpFoundation\Session\Storage\Handler;

    use \Ratchet\Session\SessionProvider;

    $pusher = new Pusher;

    $pdo = new PDO('mysql:host=localhost;dbname=community', 'root', null);

    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

    //This info is related to you db
    $dbOptions = array(
        'db_table'      => 'session',
        'db_id_col'     => 'sess_id',
        'db_data_col'   => 'sess_data',
        'db_time_col'   => 'sess_time',);

        $loop   = \React\EventLoop\Factory::create();
        $context = new \React\ZMQ\Context($loop);
        $pull = $context->getSocket(\ZMQ::SOCKET_PULL);
        $pull->bind('tcp://127.0.0.1:5555');
        $pull->on('message', array($pusher, 'onMessageEntry'));

        $webSock = new React\Socket\Server($loop);
        $webSock->listen(8080, '0.0.0.0'); // Binding to 0.0.0.0 means remotes can connect
        $webServer = new Ratchet\Server\IoServer(
            new Ratchet\Http\HttpServer(
                new Ratchet\WebSocket\WsServer(
                    new SessionProvider(
                        new Ratchet\Wamp\WampServer(
                            $pusher
                        ),new Handler\PdoSessionHandler($pdo,$dbOptions)
                    )
                )
            ),
            $webSock
        );

        $loop->run();
    ?>

Then my stub class will become:

   public function onOpen(ConnectionInterface $conn) {  
        $this->clients[$conn->Session->get('current_user_id')] = $conn;
    }

public function onMessageEntry($entry) {

            $entryData = json_decode($entry, true);
            $ReceiverConnection=$this->clients[$entryData['receiver_id']];
            $ReceiverConnection->send($entryData['message']);                  
        }

But before, I have added the user id to the session in Web server (in the controller that returns the initial page)

$user = $this->getUser();
$request->getSession()->set('current_user_id', $user->getId()); 

PS:

  1. Moving to PdoSessionHandler can be done by implementing this (Symfony).

  2. I still can't answer 2 but all the logic that can be put onMessage is now moved to onMessageEntry which satisfies temporarly the needs.




回答3:


As an alternative way to make the association between your clientConnection and his ID you need to send a message using websockets just after opening the connection to your websocket server this message will contain your user id you will use it to index his connection object by his ID in your array.

For the second question as I know the default websocket implementation is not working properly specialy with pubsub protocol you need to use a websocket library for that I suggest to use AutobahnJS it's a good websocket library with a lot of wonderfull features.



来源:https://stackoverflow.com/questions/29576033/send-user-id-from-browser-to-websocket-server-while-opening-connection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!