Home  >  Article  >  PHP Framework  >  Think-Swoole's WebSocket client message parsing and using SocketIO to process user UID and fd association

Think-Swoole's WebSocket client message parsing and using SocketIO to process user UID and fd association

藏色散人
藏色散人forward
2020-10-20 13:43:592949browse

Think-Swoole's WebSocket client message parsing and using SocketIO to process user UID and fd association

Parsing of WebSocket client messages

We demonstrated earlier that when the client connects to the server, a connection event will be triggered. In the event, we require Returns the fd of the current client. When the client sends a message to the server, the server will send the message to the client of the specified fd according to our rules:

app/listener/WsConnect.php

<?php
declare (strict_types = 1);
namespace app\listener;
class WsConnect
{
    /**
     * 事件监听处理
     *
     * @return mixed
     * 受用 WebSocket 客户端连接入口
     */
    public function handle($event)
{
        //实例化 Websocket 类
        $ws = app(&#39;\think\swoole\Websocket&#39;);
        //
        $ws -> emit(&#39;sendfd&#39;,$ws -> getSender());
    }
}

app/listener/ WsTest.php

<?php
declare (strict_types = 1);
namespace app\listener;
use \think\swoole\Websocket;
class WsTest
{
    /**
     * 事件监听处理
     *
     * @return mixed
     */
    public function handle($event,Websocket $ws)
{
        $ws -> to(intval($event[&#39;to&#39;])) -> emit(&#39;testcallback&#39;,$event[&#39;message&#39;]);
    }
}

After the client executes the above two events, the console prints out the following information:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

There are some numbers in front of the return information, 40, What does 42 mean?

Because the extension we use is based on the SocketIO protocol, these numbers can be understood as the protocol code.

Open /vendor/topthink/think-swoole/src/websocket/socketio/Packet.php, there is the following content:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

The above is the Socket type, The following is the engine. The two code names before and after are pieced together to get:

40:”MESSAGE CONNECT”
42:”MESSAGE EVENT”

Combining these codes, you can know the general operation of messages in SocketIO.

Through the messages printed out from the console, we found that these messages cannot be used directly and need to be intercepted and processed:

test.html

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
消息:<input type="text" id="message">
接收者:<input type="text" id="to">
<button onclick="send()">发送</button>
<script>
    var ws = new WebSocket("ws://127.0.0.1:9501/");
    ws.onopen = function(){
        console.log(&#39;连接成功&#39;);
    }
    //数据返回的解析
    function mycallback(data){
        var start = data.indexOf(&#39;[&#39;) // 第一次出现的位置
        var start1 = data.indexOf(&#39;{&#39;)
        if(start < 0){
            start = start1;
        }
        if(start >= 0 && start1 >= 0){
            start = Math.min(start,start1);
        }
        if(start >= 0){
            console.log(data);
            var json = data.substr(start); //截取
            var json = JSON.parse(json);
            console.log(json);
        }
    }
    ws.onmessage = function(data){
        // console.log(data.data);
        mycallback(data.data);
    }
    ws.onclose = function(){
        console.log(&#39;连接断开&#39;);
    }
    function send()
{
        var message = document.getElementById(&#39;message&#39;).value;
        var to = document.getElementById(&#39;to&#39;).value;
        console.log("准备给" + to + "发送数据:" + message);
        ws.send(JSON.stringify([&#39;test&#39;,{
            to:to,
            message:message
        }])); //发送的数据必须是 [&#39;test&#39;,数据] 这种格式
    }
</script>
</body>
</html>

Parsed data:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

Use SocketIO to process message business

For related knowledge of SocketIO, you can view the documentation, focusing on client knowledge:

https:/ /www.w3cschool.cn/socket/socket-k49j2eia.html

iotest.html

<!DOCTYPE HTML>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
消息:<input type="text" id="message">
接收者:<input type="text" id="to">
<button onclick="send()">发送</button>
<script src="./socketio.js"></script>
<script>
    //http 协议
    var socket = io("http://127.0.0.1:9501", {transports: [&#39;websocket&#39;]});
    socket.on(&#39;connect&#39;, function(){
        console.log(&#39;connect success&#39;);
    });
    socket.on(&#39;close&#39;,function(){
       console.log(&#39;connect close&#39;)
    });
    //send_fd 为自定义的场景值,和后端对应
    socket.on("sendfd", function (data) {
        console.log(data)
    });
    //testcallback 为自定义的场景值,和后端对应
    socket.on("testcallback", function (data) {
        console.log(data)
    });
    function send() {
        var message = document.getElementById(&#39;message&#39;).value;
        var to = document.getElementById(&#39;to&#39;).value;
        socket.emit(&#39;test&#39;, {
            //属性可自行添加
            to:to,
            message:message
        })
    }
</script>
</body>
</html>

var socket = io("http://127.0.0.1:9501", {transports: ['websocket']}); The second parameter specifies the protocol to be upgraded.

app/listener/WsConnect.php

<?php
declare (strict_types = 1);
namespace app\listener;
class WsConnect
{
    /**
     * 事件监听处理
     *
     * @return mixed
     * 受用 WebSocket 客户端连接入口
     */
    public function handle($event)
{
        //实例化 Websocket 类
        $ws = app(&#39;\think\swoole\Websocket&#39;);
        //
        $ws -> emit(&#39;sendfd&#39;,$ws -> getSender());
    }
}

app/listener/WsTest.php

<?php
declare (strict_types = 1);
namespace app\listener;
use \think\swoole\Websocket;
class WsTest
{
    /**
     * 事件监听处理
     *
     * @return mixed
     */
    public function handle($event,Websocket $ws)
{
//        $ws -> to(intval($event[&#39;to&#39;])) -> emit(&#39;testcallback&#39;,$event[&#39;message&#39;]);
        $ws -> to(intval($event[&#39;to&#39;])) -> emit(&#39;testcallback&#39;,[
            &#39;form&#39; => [
                &#39;id&#39; => 10,
                &#39;fd&#39; => $ws -> getSender(),
                &#39;nickname&#39; => &#39;张三&#39;
            ],
            &#39;to&#39; => [
                &#39;id&#39; => 11,
                &#39;fd&#39; => intval($event[&#39;to&#39;]),
                &#39;nickname&#39; => &#39;李四&#39;
            ],
            &#39;massage&#39; => [
                &#39;id&#39; => 888,
                &#39;create_time&#39; => &#39;2020-03-13&#39;,
                &#39;content&#39; => $event[&#39;message&#39;]
            ]
        ]);
    }
}

Open two clients, fd are 5 and 6:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

In WsConnect.php, there is $ws -> emit('sendfd',$ws -> getSender()); The scene value corresponding to the send fd message is "sendfd" , in iotest.html, there is socket.on("sendfd", function (data) {console.log(data)}); this code, which also has the scene value "sendfd", this line of code can directly obtain the corresponding scene value information, so the fd value will be printed on the console.

Use fd 5 to send information to fd 6:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

Both clients will receive the information:

Think-Swooles WebSocket client message parsing and using SocketIO to process user UID and fd association

It can be seen that the message has been parsed, because the message is sent in WsTest.php to specify the scene value testcallback, and in iotest.html, socket.on("testcallback", function (data){console.log(data)}); can be used Get the parsed results directly.

This shows the convenience of SocketIO in receiving client messages.

Binding of user UID and client fd

In the previous examples, messages are sent to the client by specifying fd. In actual scenarios, it is impossible for us to determine the sending object through fd. , because fd is not fixed, so the user's UID needs to be bound to the client's fd, and then the fd can be selected to complete the sending of the message.

You only need to add the UID parameter to the HTTP connection of the front-end page:

test.html

var ws = new WebSocket("ws://127.0.0.1:9501/?uid=1");

iotest.html

var socket = io("http://127.0.0.1:9501?uid=1", {transports: [&#39;websocket&#39;]});

The back-end can Bind in the connection event:

app/listener/WsConnect.php

<?php
declare (strict_types = 1);
namespace app\listener;
class WsConnect
{
    /**
     * 事件监听处理
     *
     * @return mixed
     * 受用 WebSocket 客户端连接入口
     */
    public function handle($event)
{
        // $event 为请求对象
        //实例化 Websocket 类
        $ws = app(&#39;\think\swoole\Websocket&#39;);
        //获取 uid
        $uid = $event -> get(&#39;uid&#39;);
        //获取 fd
        $fd = $ws -> getSender();
        //获取到 uid 和 fd 后,可以存数据库,内存或者 redis
        $ws -> emit(&#39;sendfd&#39;,[
            &#39;uid&#39; => $uid,
            &#39;fd&#39; => $fd
        ]);
    }
}

With UID and fd, you can update the database after each successful connection, and then restart after the connection is disconnected. Clear the user's FD. If the server is restarted, the corresponding relationship between the two will be useless, so there is no need to store it in the database. It is best to store it in Redis. It is also a good choice to map the relationship between the two through the Hash of Redis.

The above is the detailed content of Think-Swoole's WebSocket client message parsing and using SocketIO to process user UID and fd association. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:阿dai哥. If there is any infringement, please contact admin@php.cn delete