简体   繁体   English

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

[英]Websockets, and identifying unique peers[PHP]

i'm new to websockets. 我是websockets的新手。 Ive just completed my first multipurpose socket server, which serves 3 types of messages in the same socket. 我刚刚完成了我的第一个多用途套接字服务器,它在同一个套接字中提供3种类型的消息。 This server's intended usage is as follows: 该服务器的用途如下:

chat messages

real time market data

user specific alerts

The first two functions work great and i'm totally happy, however i am at a total loss when it comes to identifying and linking peers in the connection to specific accounts, so that i can serve pending alert notices to specific users. 前两个功能运行良好,我非常高兴,但是在识别和链接与特定帐户的连接中的对等方时,我完全失去了,因此我可以向特定用户提供待处理的警报通知。

basically, i store the alert messages in a database table like so: 基本上,我将警报消息存储在数据库表中,如下所示:

Table: uc_notifications

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

i want to store the peers in a table like so: 我想将对等体存储在一个表中,如下所示:

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

Basically, the problem i'm having is storing the peer's info in the db, and retrieving it so i can send the message to the select peer while reading the notification table. 基本上,我遇到的问题是将对等方的信息存储在数据库中,并检索它,以便我可以在读取通知表时将消息发送给选择对等方。 Everything else in the script worked. 脚本中的其他所有内容都有效。

The first thing i tried, was passing the account name to the websocket using onopen. 我尝试的第一件事是使用onopen将帐户名称传递给websocket。 this crashes the websocket. 这会使websocket崩溃。

The next thing i tried was accessing the user session through globals pertaining to the ip address. 我尝试的下一件事是通过与ip地址有关的全局变量访问用户会话。 didn't work either, and resulted in messages being received by all accounts on same ip( i was testing on localhost in all 3 browsers). 也没有工作,导致所有帐户在同一个IP上收到消息(我在所有3个浏览器中测试localhost)。

The last thing i tried, was the first method. 我尝试的最后一件事是第一种方法。 i set a timeout of 2 seconds on the on open event, then sent the account message. 我在开启事件上设置超时2秒,然后发送帐户消息。 i was able to finally store a peer in the database! 我终于能够在数据库中存储一个对等体了! but, to my chagrin when i checked the database, it said ("resource id#6). i tried casting the $clients array to globals but its empty everytime. i googled around a bit, then i tried serializing the array. it all works until i get to the part where i send the message to the unique peer. 但是,当我检查数据库时,我感到懊恼,它说(“资源ID#6)。我尝试将$ clients数组转换为全局,但每次都是空的。我google了一下,然后我尝试序列化数组。这一切工作直到我到达我发送消息给唯一同伴的部分。

here's the function for sending the message 这是发送消息的功能

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

here's an example of where i use this function to push the last 100 messages to the chatbox of the new peer. 这里是我使用此函数将最后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]);
    }

That was a few weeks ago, and i put the project on the backburner so i could move on and focus on other things. 那是几个星期前,我把这个项目放在了后面,所以我可以继续前进并专注于其他事情。 Since, i've moved to a development vps to accomadate the growing size/complexity of the application. 因为,我已经转向开发vps以适应应用程序不断增长的大小/复杂性。 instead of php, i'm using facebooks HHVM, not relevant but thought i would mention it, since it has a few quirks that forced me to alter my code a bit. 而不是PHP,我正在使用脸书HHVM,不相关,但我想提到它,因为它有一些怪癖,迫使我改变我的代码。

I have no idea about PHP, but I think this is more an approach issue rather than coding issue. 我不知道PHP,但我认为这更像是一个方法问题,而不是编码问题。 So I hope these thoughts from my experience with push architectures bring some light. 所以我希望这些来自推式架构经验的想法能带来一些启示。

Identifying users 识别用户

Identifying by cookie: 通过cookie识别:

WebSockets use a HTTP handshake that will send the cookies for that origin. WebSockets使用HTTP握手来发送该源的cookie。 You could attach an temporary ID (eg: GUID) to a special session cookie, that will be resend every time the user reconnects in the same session. 您可以将临时ID(例如:GUID)附加到特殊会话cookie,每次用户在同一会话中重新连接时,都会重新发送该ID。 You can deploy the cookie from the website as long you are honouring the Same Origin Policy, or in the HTTP handshake response itself. 只要您遵守同源策略,或者在HTTP握手响应中,您就可以从网站部署cookie。

Identifying by give token: 通过给予令牌识别:

When the WebSocket connect, you can send from the server an initial message with a token that contains a temporary ID. 当WebSocket连接时,您可以从服务器发送包含临时ID的令牌的初始消息。 That token can be resend on reconnection if the connection drops, but will be forgot if the user reload the page unless it is saved in local storage or any other kind of browser storage. 如果连接断开,该令牌可以在重新连接时重新发送,但如果用户重新加载页面将被忘记,除非它保存在本地存储或任何其他类型的浏览器存储中。

Note on temporary ID 关于临时ID的说明

How that temporary ID maps to a particular user or account, is an implementation detail you DO NOT WANT to leak to the web. 临时ID如何映射到特定用户或帐户,是您不希望泄露到Web的实现细节。 So do not use that information to identify your WS connections. 因此,请勿使用该信息来标识您的WS连接。

You should keep a "session" registry that maps temporary IDs to accounts, that maybe from a in memory dictionary, to a table on the DB. 您应该保留一个“会话”注册表,将临时ID映射到帐户,可能是从内存字典中映射到数据库上的表。 Up to you, your requirements and your service. 由您,您的要求和您的服务决定。 This element must keep reference to the WebSocket connection, so you can retrieve it by temporary ID when needed. 此元素必须保持对WebSocket连接的引用,因此您可以在需要时通过临时ID检索它。

Never leak internal details, specially account ids (because they do not change). 切勿泄漏内部细节,特别是帐户ID(因为它们不会更改)。

Receiving messages 接收消息

When receiving a message from a WebSocket, you must create a message object that contains the sender account using the "session" information you are keeping, and also the actual message content. 从WebSocket接收消息时,必须使用您保留的“会话”信息以及实际的消息内容创建包含发件人帐户的消息对象。 Then, pass this message object to your business logic that will decide what to do. 然后,将此消息对象传递给将决定要执行的操作的业务逻辑。

Before sending messages 在发送消息之前

In order to send messages, you must define first several elements: 要发送消息,您必须先定义几个元素:

Presence: 存在:

Which accounts are online? 哪些帐户在线? Merge your "session" storage with the account table. 将“会话”存储与帐户表合并。 When a connection drops, you should remove the drop user session. 当连接断开时,您应该删除drop用户会话。

Belonging: 属于:

Which accounts belong to a particular group or signal? 哪些帐户属于特定群组或信号? You must design this according to your requirements. 您必须根据您的要求进行设计。 Some groups could be predefined and indicated in the "account" entities, some other may be dynamic like he belonging to a chat room. 一些组可以预定义并在“帐户”实体中指示,一些其他组可以是动态的,就像他属于聊天室一样。 In any case, you need another element that maps "groups" to "accounts" 在任何情况下,您需要另一个将“组”映射到“帐户”的元素

Sending messages 发送消息

When your business logic decides it wants to send a message, either as response to an incoming message, as a timed action, own initiative or whatever... it must decide to which user account, user accounts or user group must be sent. 当您的业务逻辑决定要发送消息时,无论是作为对传入消息的响应,作为定时操作,还是主动或其他......它必须决定必须发送哪个用户帐户,用户帐户或用户组。

Then, using the session information that you keep, gather the list of temporary IDs that must receive that message, then the lists of WebSockets where that message must be forwarded to, and finally send the message to each of the WS of that list. 然后,使用您保留的会话信息,收集必须接收该消息的临时ID列表,然后是必须转发该消息的WebSockets列表,最后将消息发送到该列表的每个WS。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM