Ratchet PHP Websockets:私人消息传递(控制消息发送给谁)

Posted

技术标签:

【中文标题】Ratchet PHP Websockets:私人消息传递(控制消息发送给谁)【英文标题】:Ratchet PHP Websockets: Private messaging (control who messages are being sent to) 【发布时间】:2016-08-11 16:40:12 【问题描述】:

还有一个问题。 我开始习惯 websocket 的工作方式。 我什至设法实现了跨域通信。 但现在我还没有达到另一个里程碑。

这是我当前实现的一个 sn-p

 public function onMessage(ConnectionInterface $conn, $msg)

     $msgjson = json_decode($msg);
     $tag = $msgjson->tag;
     global $users; 

     if($tag == "[msgsend]")
     

            foreach($this->clients as $client)
            
                  $client->send($msg);    
            
     
     else if($tag == "[bye]")
     

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

         foreach($users as $key => $user)
         
             if($user->name == $msgjson->uname)
             
                unset($users[$key]); 
             
         

         $this->clients->detach($conn);
     
     else if($tag == "[connected]")
     
         //store client information
         $temp = new Users();
         $temp->name = $msgjson->uname;
         $temp->connection = $conn;
         $temp->timestamp = new \DateTime();



         $users[] = $temp;





          usort($users, array($this, "cmp"));


         //send out messages
          foreach($this->clients as $client)
         
              $client->send($msg);    
                    

     
     else if($tag == "[imalive]")
     
         //update user timestamp who sent [imalive]
         global $users;

          foreach($users as $user)
             
                if($msgjson->uname == $user->name)
                
                        $user->timestamp = new \DateTime(); 
                
             

        


现在我的问题是。正如我们所看到的,在 onMessage() 函数和我做过的教程中,我知道如何读取和解析 JSON 数据,理解消息,知道消息来自谁($conn)......

但是,当我在 JSON 数据包中发送消息时,我想包括消息来自谁的昵称以及消息将要发送给谁。 这将允许我在我正在构建的社交网络和聊天室中实现私人即时消息传递。

我只想向特定的客户端发送消息,而不是使用 for 循环向所有连接的客户端发送消息。我知道客户有一个属性($this->$client->resourceID 或类似的东西),但也不知道如何将它合并为解决方案。我还希望用户在跳转到网站上的不同页面时保持连接,即使在刷新后,仍然能够继续发送消息。我假设每次刷新都会断开客户端的连接。所以我必须有一种方法,让服务器每次都能知道谁是谁,消息来自哪里以及它们要去哪里。

但是,是的,私人消息。我不想向所有人或非预期目标发送不必要的信息。我怎样才能做到这一点? 我希望我的问题是有道理的。谢谢。

【问题讨论】:

如果某个答案解决了您的问题,请考虑接受该答案。以下是meta.stackexchange.com/questions/5234/… 然后返回此处并对勾号/复选标记执行相同操作直到它变为绿色的方法。这通知社区,找到了解决方案。否则,其他人可能会认为问题仍然悬而未决,可能想要发布(更多)答案。您将获得积分,并鼓励其他人帮助您。 欢迎来到 Stack! 如果您认为这是不友好的,那么我建议您不了解社区以及投票的含义。否决票(将鼠标悬停在向下箭头上)意味着选民认为该问题没有得到很好的研究或没有表现出任何努力。当你出轨时,你会吸引额外的眼球,突然你的积分水平像摩天大楼上的石头一样下降。这不是个人的,这些选票尤其不应该是。我在上面发布的内容是“如果”,而不是“你必须”。这只是一个建议。如果您没有获得帮助,请询问如何获得帮助。不要咒骂、尖叫和踢你的脚 我的 cmets 被删除的方式很有趣(因为你知道我是对的)但你的回复不是。不。我不了解社区或我的问题如何“没有用”或“没有显示任何研究工作”(当我将鼠标悬停在向下箭头上时,这就是它所说的)。研究了另一个线程中的问题。在我什至在这里询问它之前,我花了几天的时间。最终,在前几天的粗鲁之后,我自己弄清楚了,这是一个比这里任何其他人建议的更容易的解决方案。但是我不会发布解决方案,因为您不应该得到这些信息。 你的cmets不是我删除的,我没有那种权力。 mod是唯一可以删除cmets的。如果您的 cmets 不具有建设性、粗鲁或冒犯性,它们最终将被删除。如果您不想发布一个很好的解决方案,那么它不会从任何人的鼻子上掉下来。 【参考方案1】:

能够唯一标识连接到您的 WebSocket 服务器的用户,然后能够定位这些用户,特别是在发送消息时需要从实际与服务器协商连接的 onOpen 回调开始。

在您的onOpen 方法中,您应该有某种方法通过全局存储在您的数据库或持久性存储中的某个用户ID 来唯一地识别系统上的用户。由于连接是通过 HTTP 协商的,因此您可以通过 $conn->WebSocket->request 访问 HTTP 请求,这是一个包含客户端 HTTP 请求信息的 GuzzleHttp 对象。例如,您可以使用它来提取一个 cookie,其中包含一些用户 ID 数据或令牌,您可以将其与数据库进行比较以确定用户是谁,然后将其存储为 $client 对象的属性。

现在,让我们假设您正在编写一个普通的 php 脚本,您在其中通过 HTTP 进行用户身份验证并将用户 ID 存储在会话中。此会话在客户端机器上设置一个包含会话 ID 的 cookie(默认情况下,cookie 名称是会话名称,通常为 PHPSESSID,除非您更改它)。这个 session id 可以在你的 WebSocket 服务器中使用来访问 session 存储,就像在 PHP 中一样。

这是一个简单的例子,我们期望请求中的一个名为 PHPSESSID 的 cookie 从 cookie 中捕获会话 id。

public function onOpen(ConnectionInterface $conn) 
    // extract the cookie header from the HTTP request as a string
    $cookies = (string) $conn->WebSocket->request->getHeader('Cookie');
    // look at each cookie to find the one you expect
    $cookies = array_map('trim', explode(';', $cookies));
    $sessionId = null;
    foreach($cookies as $cookie) 
        // If the string is empty keep going
        if (!strlen($cookie)) 
            continue;
        
        // Otherwise, let's get the cookie name and value
        list($cookieName, $cookieValue) = explode('=', $cookie, 2) + [null, null];
        // If either are empty, something went wrong, we'll fail silently here
        if (!strlen($cookieName) || !strlen($cookieValue)) 
            continue;
        
        // If it's not the cookie we're looking for keep going
        if ($cookieName !== "PHPSESSID") 
            continue;
        
        // If we've gotten this far we have the session id
        $sessionId = urldecode($cookieValue);
        break;
    
    // If we got here and $sessionId is still null, then the user isn't logged in
    if (!$sessionId) 
        return $conn->close(); // close the connection - no session!
    

现在您实际上拥有$sessionId,您可以使用它来访问该会话的会话存储,将会话信息拉入您的WebSocket 服务器并将其存储为客户端连接对象$conn 的属性。

因此,继续上面的示例,让我们将此代码添加到 onOpen 方法中。

public function onOpen(ConnectionInterface $conn) 
    $conn->session = $this->methodToGetSessionData($sessionId);
    // now you have access to things in the session
    $this->clinets[] = $conn;

现在,让我们回到您希望专门向一位用户发送消息的示例。假设我们在会话中存储了以下属性,现在可以从客户端连接对象访问这些属性...

$conn->session->userName = 'Bob';
$conn->session->userId   = 1;

假设 Bob 想向 Jane 发送消息。一个请求进入您的 WS 服务器,带有类似 "from":1,"to":2,tag:"[msgsend]" 的内容,其中该 JSON 的 tofrom 属性基本上是消息来自 的用户的用户 ID,而用户是消息旨在分别发送。对于这个例子,我们假设 Jane 是 userId = 2

public function onMessage(ConnectionInterface $conn, $msg) 
    $msgjson = json_decode($msg);
    $tag = $msgjson->tag;
    if ($tag == '[msgsend]') 
        foreach($this->clients as $client) 
            // only send to the designated recipient user id
            if ($msgjson->to == $client->session->userId) 
                $client->send($msg);    
            
        
    

显然,您可能希望在其中进行更详细的验证,但您应该能够从这里对此进行扩展。

【讨论】:

$conn->WebSocket->request->getHeader('Cookie');现在改为 $conn->httpRequest->getHeader('Cookie');在新棘轮上

以上是关于Ratchet PHP Websockets:私人消息传递(控制消息发送给谁)的主要内容,如果未能解决你的问题,请参考以下文章

使用 Ratchet Websockets 进行 PHP 实时聊天

如何在 MAMP 或 XAMPP 上安装 Ratchet WebSockets for PHP?

Ratchet Websockets - 灌输问题

WebSockets + PHP(棘轮)登录系统

如何使实时服务器 Ratchet WebSockets 工作?

iis8 上 WSS 上的 Ratchet Websockets