Websockets,并识别唯一的对等[PHP]

时间:2014-04-16 06:12:38

标签: php sockets websocket

我是websockets的新手。我刚刚完成了我的第一个多用途套接字服务器,它在同一个套接字中提供3种类型的消息。该服务器的预期用途如下:

chat messages

real time market data

user specific alerts

前两个功能运行良好,我感到非常高兴,但是在识别和链接与特定帐户的连接中的对等方时,我完全不知所措,这样我就可以将特定的警报通知提供给特定的用户。

基本上,我将警报消息存储在数据库表中,如下所示:

Table: uc_notifications

account(varchar50) | message(varchar255) | id(primary,AI) | seen(default 0)

我想将对等体存储在一个表中,如下所示:

uc_notification_peers
account(varchar50) | peer_id(unique,varchar100) | id(primary,AI)

基本上,我遇到的问题是将对等体的信息存储在数据库中,然后检索它,这样我就可以在读取通知表时将消息发送给选择对等体。脚本中的其他所有内容都有效。

我尝试的第一件事是使用onopen将帐户名称传递给websocket。这会使websocket崩溃。

我尝试的下一件事是通过与ip地址有关的全局变量访问用户会话。也没有工作,并导致所有帐户在同一个IP上收到消息(我在所有3个浏览器中测试localhost)。

我尝试的最后一件事是第一种方法。我在开启事件上设置超时2秒,然后发送帐户消息。我终于能够在数据库中存储一个对等体了!但是,当我检查数据库时,我感到懊恼,它说("资源ID#6)。我尝试将$ clients数组转换为全局变量但每次都是空的。我google了一下,然后我尝试序列化数组。这一切都有效,直到我到达我将消息发送给唯一同伴的部分。

这里是发送消息的功能

function send_message_single_client($msg,$client) 
{
    @socket_write($client,$msg,strlen($msg));
    return true;
}

这里是我使用此功能将最后100条消息推送到新对等方的聊天框的示例。

if (in_array($socket, $changed)) {
        $socket_new = socket_accept($socket);
        $clients[] = $socket_new;
        $header = socket_read($socket_new, 1024);
        perform_handshaking($header, $socket_new, $host, $port);
        socket_getpeername($socket_new, $ip);
        $found_socket = array_search($socket, $changed);
        //need to push last 100 messages to new peer.
        $query = $mysqli->query("SELECT * FROM (SELECT * FROM uc_chat_msg WHERE `hidden`='0' ORDER BY `id` DESC LIMIT 100) as last100 ORDER BY id");
        while($row = $query->fetch_assoc()) {
            $response_text = mask(json_encode(array('type'=>'usermsg', 'name'=>security($row["username"]), 'message'=>security($row["message"]), 'color'=>security($row["color"]))));
            send_message_single_client($response_text, $socket_new);//send old messages to the new client
        }
        $query->close();
        unset($changed[$found_socket]);
    }

那是几个星期前,我把这个项目放在了后面,所以我可以继续前进并专注于其他事情。因为,我已经转移到开发vps,以适应应用程序不断增长的大小/复杂性。而不是PHP,我使用的是Facebook HHVM,不相关,但我想我会提到它,因为它有一些怪癖迫使我改变我的代码。

1 个答案:

答案 0 :(得分:5)

我不知道PHP,但我认为这更像是一个方法问题,而不是编码问题。所以我希望这些来自推动架构经验的想法能带来一些启发。

识别用户

通过cookie识别:

WebSockets使用HTTP握手来发送该源的cookie。您可以将临时ID(例如:GUID)附加到特殊会话cookie,每次用户在同一会话中重新连接时,都会重新发送该ID。只要您遵守同源策略,或者在HTTP握手响应中,您就可以从网站部署cookie。

通过给予令牌识别:

当WebSocket连接时,您可以从服务器发送包含临时ID的令牌的初始消息。如果连接断开,该令牌可以在重新连接时重新发送,但如果用户重新加载页面将被忘记,除非它被保存在本地存储或任何其他类型的浏览器存储中。

关于临时ID

的说明

该临时ID如何映射到特定用户或帐户,是您不希望泄露到Web的实现细节。所以不要使用该信息来识别您的WS连接。

您应该保留一个“会话”注册表,将临时ID映射到帐户,可能是从内存字典中映射到数据库上的表。由您,您的要求和您的服务决定。此元素必须保持对WebSocket连接的引用,因此您可以在需要时通过临时ID检索它。

绝不泄漏内部细节,特别是帐户ID(因为它们不会更改)。

接收消息

从WebSocket接收消息时,您必须使用您保留的“会话”信息以及实际的消息内容创建包含发件人帐户的消息对象。然后,将此消息对象传递给将决定要执行的操作的业务逻辑。

发送消息之前

要发送消息,您必须先定义几个元素:

存在:

哪些帐户在线?将“会话”存储与帐户表合并。当连接断开时,您应该删除drop用户会话。

所有物:

哪些帐户属于特定群组或信号?您必须根据您的要求进行设计。一些组可以预定义并在“帐户”实体中指示,一些其他组可以是动态的,就像他属于聊天室一样。无论如何,您需要另一个将“群组”映射到“帐户”的元素

发送消息

当您的业务逻辑决定要发送消息时,无论是作为对传入消息的响应,作为定时操作,还是主动或其他......它必须决定哪个用户帐户,用户帐户或用户组必须是发送。

然后,使用您保留的会话信息,收集必须接收该消息的临时ID列表,然后是必须转发该消息的WebSockets列表,最后将消息发送到该消息的每个WS列表。