本文介绍了打开连接时将用户 ID 从浏览器发送到 websocket 服务器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在问这个问题之前,我尽力阅读了关于 SO 的问题(标记 Ratchet 并处理类似问题,但要徒劳无功.我什至问了一个没有引起注意的问题,我因此删除它来写另一个(希望更多清除).

我的最终目标是使用 Ratchet 构建一个一对一的私人聊天应用程序.一切正常,只是我无法向特定用户发送消息.

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.

每个登录的用户在访问网站的安全区域时都连接到 websocket 服务器:

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);
        };

});

当用户在聊天框中写一条消息时,该消息通过 AJAX 发送到 Web 服务器,然后使用 ZeroMQ 推送到 Websocket.在控制器中:

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));

所以最后,我的 websocket 服务器能够使用 JSON 知道哪个是接收器的 id.但是他怎么知道那个用户的连接是什么?换句话说,我需要将 websocket 连接存储在一个由用户 id 索引的数组中.

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;
    }
}

和 websocket 服务器:

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();

        ?>

问题:

  1. 如何在打开连接时从客户端发送登录的 user_id.我需要在 websocket 服务器中拥有该值,以便我可以用它索引我的客户端数组($client[user_id]=$conn 而不是 $client[recourceId]=$conn).我尝试了 javascript 函数 send 但我不知道从哪里接收发送的数据(即使 onMessage 没有打印任何内容).

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

为什么 onMessage 方法即使实现了 MessageComponentInterface 也没有执行(是因为我有 onMessageEntry 方法 + $pull->on('message', array($pusher, 'onMessageEntry')); 一行代码?

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?

谢谢.

推荐答案

这是我的发现,欢迎提出任何改进此解决方案的建议.

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

可以使用 Ratchet SessionProvider.这将需要使用所示的 Symfony 自定义会话处理程序之一.我在下面的代码中使用了 PdoSessionHandler.

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']);
        }

但之前,我已经将用户 ID 添加到 Web 服务器中的会话中(在返回初始页面的控制器中)

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());

附注:

  1. 移动到 PdoSessionHandler 可以通过实现this(Symfony).

我仍然无法回答 2 但所有可以放在 onMessage 上的逻辑现在都移到了 onMessageEntry 中,暂时满足了需求.

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.

这篇关于打开连接时将用户 ID 从浏览器发送到 websocket 服务器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-23 01:22