【问题标题】:How to send messages to particular users Ratchet PHP Websocket如何向特定用户发送消息 Ratchet PHP Websocket
【发布时间】:2015-06-20 11:45:47
【问题描述】:

我正在尝试构建一个系统,用户可以在建立与 websocket 服务器的连接时订阅一个类别,然后他将开始接收该类别的更新。到目前为止,我已经与 Ratchet 合作过,我能够向所有连接的客户端发送消息,但问题是我不想向所有客户端发送消息我只想将消息发送给订阅的客户端发送消息的特定类别。

PHP 代码

聊天.php

<?php
namespace MyApp;
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;

class Chat implements MessageComponentInterface
{
    protected $clients;

    public function __construct()
    {
        $this->clients = new \SplObjectStorage;
    }

    public function onOpen(ConnectionInterface $conn)
    {
        $this->clients->attach($conn);
    }

    public function onMessage(ConnectionInterface $conn, $msg)
    {
        foreach ($this->clients as $client)
        {
            if($conn !== $client)
                $client->send($msg);
        }
    }

    public function onClose(ConnectionInterface $conn)
    {
        $this->clients->detach($conn);
    }

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

server.php

<?php
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use MyApp\Chat;

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

$server = IoServer::factory(
  new HttpServer(
    new WsServer(
      new Chat()
    )
  ),
  8080
);

$server->run();
?>

客户端js代码

<script type="text/javascript">
var conn = new WebSocket('ws://localhost:8080');

conn.onopen = function(e) {
  console.log("Connection established!");
};

conn.onmessage = function(e) {
  console.log(e.data);
};
</script>

【问题讨论】:

    标签: php websocket real-time ratchet


    【解决方案1】:

    基本上,您需要一种将数据发送到 WebSocket 的语法,我建议使用 JSON 对象来执行此操作。在您的 WebSocket 类中,您需要一个名为 subscriptions 的局部变量和一个名为 users 的局部变量,就像这样。

    <?php
    namespace MyApp;
    use Ratchet\MessageComponentInterface;
    use Ratchet\ConnectionInterface;
    
    class Chat implements MessageComponentInterface
    {
        protected $clients;
        private $subscriptions;
        private $users;
    
        public function __construct()
        {
            $this->clients = new \SplObjectStorage;
            $this->subscriptions = [];
            $this->users = [];
        }
    
        public function onOpen(ConnectionInterface $conn)
        {
            $this->clients->attach($conn);
            $this->users[$conn->resourceId] = $conn;
        }
    
        public function onMessage(ConnectionInterface $conn, $msg)
        {
            $data = json_decode($msg);
            switch ($data->command) {
                case "subscribe":
                    $this->subscriptions[$conn->resourceId] = $data->channel;
                    break;
                case "message":
                    if (isset($this->subscriptions[$conn->resourceId])) {
                        $target = $this->subscriptions[$conn->resourceId];
                        foreach ($this->subscriptions as $id=>$channel) {
                            if ($channel == $target && $id != $conn->resourceId) {
                                $this->users[$id]->send($data->message);
                            }
                        }
                    }
            }
        }
    
        public function onClose(ConnectionInterface $conn)
        {
            $this->clients->detach($conn);
            unset($this->users[$conn->resourceId]);
            unset($this->subscriptions[$conn->resourceId]);
        }
    
        public function onError(ConnectionInterface $conn, \Exception $e)
        {
            echo "An error has occurred: {$e->getMessage()}\n";
            $conn->close();
        }
    }
    ?>
    

    与之配套的 javascript 看起来有点像这样

    <script type="text/javascript">
    var conn = new WebSocket('ws://localhost:8080');
    
    conn.onopen = function(e) {
      console.log("Connection established!");
    };
    
    conn.onmessage = function(e) {
      console.log(e.data);
    };
    
    function subscribe(channel) {
        conn.send(JSON.stringify({command: "subscribe", channel: channel}));
    }
    
    function sendMessage(msg) {
        conn.send(JSON.stringify({command: "message", message: msg}));
    }
    </script>
    

    注意:此代码未经测试,我是根据我使用 Ratchet 的经验即时编写的。祝你好运:)

    【讨论】:

    • 其实我需要使用 Ratchet Pusher。而且我已经做到了一切正常,但现在的问题是,客户端在空闲几分钟后断开连接而没有任何断开连接消息它停止接收消息。如果我每 10 分钟向客户端发送消息,它不会断开连接,但如果间隔超过 20 分钟左右,客户端不会收到消息。
    • @RohitKhatri 你用什么连接到 websocket?你是通过 nginx 代理还是什么的?
    • 我在这个例子中使用带有 Pusher 的 Ratchet link
    • 此外,此方法 100% 有效,您所需要做的就是映射您的应用流程
    • 你能解释一下为什么首先使用$this-&gt;clients = new \SplObjectStorage - 除了没有其他目的使用attach / detach吗?您的所有连接现在都存储在private $users 中。有什么我想念的吗?
    【解决方案2】:

    好的,现在我分享我的经验。您可以发送令牌并在数据库中的 onOpen (server.php) 中插入此令牌。您可以在用户登录时插入聊天令牌。每次用户登录时都会生成和更新新令牌。 现在使用这个令牌来找出 onOpen 连接中的用户 ID。

    var conn = new WebSocket('ws://172.16.23.26:8080?token=<?php echo !empty($_SESSION['user']['token']) ? $_SESSION['user']['token'] : ''; ?>');    
        conn.onopen = function(e) {
            console.log("Connection established!");
        };
    

    现在服务器.php

      public function onOpen(ConnectionInterface $conn) {
        $this->clients->attach($conn);      
        $querystring = $conn->httpRequest->getUri()->getQuery();
        parse_str($querystring,$queryarray);
       //Get UserID By Chat Token
        $objUser = new \users;
        $objUser->setLoginToken($queryarray['token']);
        $GetUserInfo = $objUser->getUserByToken();
        echo "New connection! ({$conn->resourceId})\n";
        //save Chat Connection
       // Insert the new connection with the user ID to Match to later if user ID in Table Then Update IT with a new connection 
    
     }
    

    现在您的连接已建立,然后向特定用户发送消息

    客户端发送 USerID 和接收到的 ID 和消息

    $("#conversation").on('click', '#ButtionID', function () {
             var userId      = $("#userId").val();
             var msg         = $("#msg").val();         
             var receiverId  = $("#receiverId").val();
          if ( userId  != null &&  msg  != null ){
            var data = {
                userId: userId,
                msg: msg,
                receiverId: receiverId
            };
            conn.send(JSON.stringify(data));
            $("#msg").val("");  
          }                 
        });
    

    服务器端

    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');
          $data = json_decode($msg, true);
          echo $data['userId'];
          echo $data['msg'];
          echo $data['receiverId'];
         // Save User ID receiver Id message in table 
         //Now Get Chat Connection by user id By Table Which is saved onOpen function    
            $UptGetChatConnection   = $objChatroom->getChatConnectionUserID($data['receiverId']);
        $ReciId = $UptGetChatConnection[0]['ConnectionID'];
        foreach ($this->clients as $client) {
            if ($from == $client) {
               $data['from']  = "Me";
               $data['fromname'] = 5;
            } else {
               $data['from']  = $user['name'];
               $data['fromname'] = 6;
            }
            echo $client->resourceId;
            echo $ReciId."\n";
            if($client->resourceId == $ReciId || $from == $client){
                $client->send(json_encode($data));
            }
        }
    } 
    

    现在消息已经通过连接 ID 发送而不是广播只发送特定的 用户

    【讨论】:

      【解决方案3】:
      // SOCKET VARIABLE DECLARATION
      var mySocket;
      
      // MESSAGE
      const socketMessageListener = function(event) {
          var data = JSON.parse(event.data);
      };
      
      // OPEN SOCKET
      const socketOpenListener = function(event) {
          console.log('Connected');
      };
      
      // CLOSE OR DISCONNECT SOCKET
      const socketCloseListener = function(event) {
          if (mySocket) {
              console.error('Disconnected.');
          }
          mySocket = new WebSocket('ws://localhost:8080');
          mySocket.addEventListener('open', socketOpenListener);
          mySocket.addEventListener('message', socketMessageListener);
          mySocket.addEventListener('close', socketCloseListener);
      };
      
      // CALL THE LISTENER
      socketCloseListener();
      
      function sendMessage(data) {
          mySocket.send(JSON.stringify(data));
      }
      

      user3049006 我在研究中发现此代码可在失败重试连接时保持连接持久。

      【讨论】:

        猜你喜欢
        • 2016-02-16
        • 2015-08-25
        • 2020-05-06
        • 2014-04-17
        • 1970-01-01
        • 2012-10-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多