【问题标题】:Send user ID from browser to websocket server while opening connection在打开连接时将用户 ID 从浏览器发送到 websocket 服务器
【发布时间】:2015-06-17 00:49:36
【问题描述】:

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

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

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

$(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。在控制器中:

// 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 索引的数组中。

<?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 服务器:

  <?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 而不是@987654327 @)。我尝试了javascript函数send,但我不知道在哪里接收发送的数据(即使onMessage没有打印任何东西)。

  2. 为什么onMessage方法甚至MessageComponentInterface都没有执行(是因为我有onMessageEntry方法+$pull-&gt;on('message', array($pusher, 'onMessageEntry'));这行代码吗?

谢谢。

【问题讨论】:

    标签: websocket real-time zeromq ratchet


    【解决方案1】:

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

    可以使用棘轮SessionProvider。这将需要使用所示的 Symfony 自定义会话处理程序之一。我在以下代码中使用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();
        ?>
    

    那么我的存根类会变成:

       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 服务器中的会话中(在返回初始页面的控制器中)

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

    PS:

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

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

    【讨论】:

      【解决方案2】:

      作为在您的clientConnection 和他的ID 之间建立关联的另一种方法,您需要在打开与您的 websocket 服务器的连接后使用 websockets 发送一条消息,此消息将包含您的用户 ID,您将使用它来通过他的ID 在你的数组中索引他的连接对象。

      对于第二个问题,我知道默认的 websocket 实现不能正常工作,特别是 pubsub 协议,你需要使用 websocket 库,我建议使用 AutobahnJS 这是一个很好的 websocket 库,有很多精彩功能。

      【讨论】:

      • 感谢 Anas 的一贯贡献。你的选择是我尝试的第一件事。我在使用send 函数打开连接时使用了javascript,但我找不到在Pusher 类中获取值的方法。您的解决方案是我真正寻找的,并且使用了 SessionProvider 因为我失败了。在 websocket 服务器中从哪里获取发送的 id?\
      • 您没有收到数据,因为 web 浏览器中 websockets 的默认实现不能与 pubsub 协议正常工作 尝试将它与 AuthobahnJS 一起使用它有一个 pubsub 协议的实现。
      • 看看这个,我没有使用 PDOSessionProvider 因为会话没有与你的连接对象相同的生命周期看看这个groups.google.com/forum/#!topic/ratchet-php/LNCsDIugvBg
      • 好吧,我明白你的意思了。我将尝试使用 AuthobanhnJS 并提供反馈。感谢谷歌群组链接
      【解决方案3】:

      实际上,在我最后一次尝试中,我放弃了 PHP WebSocket(完成这项工作非常复杂)并开始使用带有 nodeJS 的 SocketIO,它解决了我的整个问题,并且可以给我一个功能简单的聊天系统。

      【讨论】:

      • 感谢您与整个社区分享您的经验。
      猜你喜欢
      • 2014-07-20
      • 1970-01-01
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-04
      • 2015-09-15
      • 2014-03-12
      相关资源
      最近更新 更多