如何获取特定用户的连接对象?

Posted

技术标签:

【中文标题】如何获取特定用户的连接对象?【英文标题】:how to get the connection object of a specific user? 【发布时间】:2013-07-09 03:58:33 【问题描述】:

我正在使用 Ratchet 库的实时 Symfony 应用程序中工作,在这个应用程序中,我需要向特定用户发送一些数据,因此逻辑解决方案是使用SessionProvider 会将 Symfony2 Session 对象附加到每个传入的 Connection 对象。 正如文档所述,我已经设置了一个非本地会话处理程序来存储我的会话,即通过 PDO 在数据库中。 目前工作正常,但我需要让特定用户的 Connection 对象向他发送一些数据,所以以其他方式我需要找到引用该用户的连接对象,但我找不到办法它 ? 她是我的服务器代码:

    $app=new AggregateApplication();
    $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($app, 'onNotification'));
    $webSock = new \React\Socket\Server($loop);
    $webSock->listen(8080, '127.0.0.1');
    $handler = $this->getContainer()->get('session.handler');
    $server=new \Ratchet\Wamp\WampServer($app);
    $server = new SessionProvider($server, $handler);
    $webServer = new \Ratchet\Server\ioserver(new \Ratchet\WebSocket\WsServer($server),$webSock);
    $loop->run();

【问题讨论】:

但是如何向特定用户发送消息?如何在连接到一个 WebSocket 服务器的 2 个客户端的示例中实现这一点,每个客户端都有自己的连接对象:$ConnSender,$ConnReceiver?请向我澄清一下,我在 SO.thanks 的棘轮标签上找不到任何答案 绝对没有必要,但是建议您从客户端发送到服务器的每个数据都需要在 http 请求中使用 ajax 完成,然后您应该使用 ZMQ 告诉 webSocketServer 将相同的数据发送到另一个客户端使用 webSockets,因为如果您在 websocket 服务器中处理数据,这是一个安全问题。即使您使用链接中的线程,您也会通过线程中的重新应用程序代码 正是我的解决方案。 非常感谢先生分享您的经验,特别是php编程这部分确实缺乏简单明了的文档(考虑到新手)。 我已经发布了回复希望对您有所帮助。 【参考方案1】:

我自己也有同样的问题(减去 Symfony),这就是我所做的。

基于hello world tutorial,我用数组替换了SplObjectStorage。在展示我的修改之前,我想评论一下,如果您遵循该教程并理解它,那么阻止您自己获得此解决方案的唯一可能就是不知道 SplObjectStorage 是什么。

class Chat implements MessageComponentInterface 
    protected $clients;

    public function __construct() 
        $this->clients = array();
    

    public function onOpen(ConnectionInterface $conn) 
        // Store the new connection to send messages to later
        $this->clients[$conn->resourceId] = $conn;
        echo "New connection! ($conn->resourceId)\n";
    

    public function onMessage(ConnectionInterface $from, $msg) 
        $numRecv = count($this->clients) - 1;
        echo sprintf('Connection %d sending message "%s" to %d other connection%s' . "\n"
            , $from->resourceId, $msg, $numRecv, $numRecv == 1 ? '' : 's');

        foreach ($this->clients as $key => $client) 
            if ($from !== $client) 
                // The sender is not the receiver, send to each client connected
                $client->send($msg);
            
        
        // Send a message to a known resourceId (in this example the sender)
        $client = $this->clients[$from->resourceId];
        $client->send("Message successfully sent to $numRecv users.");
    

    public function onClose(ConnectionInterface $conn) 
        // The connection is closed, remove it, as we can no longer send it messages
        unset($this->clients[$conn->resourceId]);

        echo "Connection $conn->resourceId has disconnected\n";
    

    public function onError(ConnectionInterface $conn, \Exception $e) 
        echo "An error has occurred: $e->getMessage()\n";

        $conn->close();
    

当然,为了让它真正有用,您可能还想添加一个数据库连接,并存储/检索这些资源 ID。

【讨论】:

认为我已经有了这个解决方案,但我只是想知道为什么在 Rachet 的官方文档中他们说我们需要使用会话处理程序将每个连接对象附加到 symfony 会话......如果我们可以仅使用客户端的 sqlObjectStorage 和 Id 来执行此操作? 我认为他们的意思是:“授予您对网站会话数据的只读访问权限。” 如果我自己更改资源 ID 会怎样?这就是我正在做的事情:每当我建立连接时,我都会立即发送一条消息,其中包含该用户的实际 id(不是他的 resourceId,我说的是我用来获取用户的名字、姓氏等的 id ( id,我给他发信息。我应该这样做吗?替换 resourceIds 是否安全?【参考方案2】:

这就是我所做的,对相同的想法进行了一些改进。

添加了 2 个可以在其他地方调用的函数:send_to() 和 multicast()。

namespace mine;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class ws implements MessageComponentInterface 
    protected $clients;
    protected $clientids;

    public function __construct() 
        $this->clients = new \SplObjectStorage; 
        $this->clientids = array();
    

    public function multicast($msg) 
        foreach ($this->clients as $client) $client->send($msg);
    

    public function send_to($to,$msg) 
        if (array_key_exists($to, $this->clientids)) $this->clientids[$to]->send($msg);
    

    public function onOpen(ConnectionInterface $conn) 
        $socket_name = "$conn->resourceId@$conn->WebSocket->request->getHeader('X-Forwarded-For')";
        $this->clients->attach($conn,$socket_name);
        $this->clientids[$socket_name] = $conn;
    

    public function onMessage(ConnectionInterface $from, $msg) 
        $this->multicast($msg);
    

    public function onClose(ConnectionInterface $conn) 
        unset($this->clientids[$this->clients[$conn]]);
        $this->clients->detach($conn);
    

    public function onError(ConnectionInterface $conn, \Exception $e) 
        $conn->close();
    

【讨论】:

以上是关于如何获取特定用户的连接对象?的主要内容,如果未能解决你的问题,请参考以下文章

我们如何在 Flutter 中从 JSON 对象中获取特定数据?

如何从props传递对象获取默认日期为特定日期

如何在 Laravel 中将连接结果作为对象数组获取?

如何获取配对的 BLE 设备数量?

如何创建获取请求以获取具有特定属性值的对象

如何在 django admin 中获取对象的历史记录?