javascript - Ratchet PHP Websocket : Private messaging (control who messages are being sent to)

标签 javascript php jquery websocket ratchet

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

这是我当前实现的一个片段

 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 数据包中发送消息时,我想包含消息的发件人以及消息的收件人的昵称。 这将使我能够在我正在构建的社交网络和聊天室中实现私有(private)即时消息传递。

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

但是,是的,私有(private)消息。我不想向每个人或非预期目标发送不必要的消息。我怎样才能做到这一点? 我希望我的问题有意义。谢谢。

最佳答案

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

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

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

这是一个简单的示例,我们期望请求中有一个名为 PHPSESSID 的 cookie,以从 cookie 中捕获 session 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,您可以使用它来访问该 session 的 session 存储,将 session 信息拉入您的 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;
}

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

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

假设鲍勃想向简发送消息。请求以类似 {"from":1,"to":2,tag:"[msgsend]"} 的形式传入您的 WS 服务器,其中 to 和该 JSON 的 from 属性基本上是消息的发件人的用户 ID 以及消息要发送到的用户的用户 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);    
            }
        }
    }
}

显然,您可能希望在那里进行更精细的验证,但您应该能够从这里进行扩展。

关于javascript - Ratchet PHP Websocket : Private messaging (control who messages are being sent to),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38901913/

相关文章:

javascript - 无法使用 sortable 对数据进行排序

javascript - jQuery DataTable 在按钮单击上设置标题

javascript - Ajax Jqgrid 重新加载网格不工作 c# .net

javascript - Angular 2将html附加到正文

javascript - 如何在 Javascript 中使用 AM/PM 创建时间正则表达式

javascript - 如何克服javascript的56位限制

javascript - 在 Laravel5.0 中将 google chart 与 mysql 数据库中的数据集成

javascript - 将图标设置为将插入事件的元素

php - MySql SELECT 从多条记录中获取1条记录

php - json_encode正在截断从mysql数据库读取的对象数据