Home > Backend Development > PHP Tutorial > Case study of the combination of ThinkPHP5.1 framework and Workerman's GatewayWorker framework

Case study of the combination of ThinkPHP5.1 framework and Workerman's GatewayWorker framework

藏色散人
Release: 2023-04-05 19:32:01
forward
8738 people have browsed it

GatewayWorker is a distributed deployable TCP long connection framework developed based on Workerman. It is specially used to quickly develop TCP long connection applications, such as app push servers, instant IM servers, game servers, Internet of Things, and smart homes. Wait

Document address: http://www.workerman.net/gatewaydoc/

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

1. Test the official DEMO (Windows version)

1. Download the demo (Get your own in the comments below)

2. Unzip it to any location, here is:

D:\phpStudy\PHPTutorial\WWW\GatewayWorker
Copy after login

3. Enter the GatewayWorker directory

4. Double-click start_for_win.bat to start. (If an error occurs, please refer to here to set the php environment variable), the effect is as follows

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

5. Run telnet 127.0.0.1 8282 in the command line window, enter any characters to chat (not For local testing, please replace 127.0.0.1 with the actual IP).

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

PS: The above indicates that the TCP connection test is successful

2. Modify the test websocket

1. Need to modify start_gateway.php specifies the websocket protocol, like this

$gateway = new Gateway(websocket://0.0.0.0:7272);
Copy after login

2. Restart start_for_win.bat

3. Test js

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

Summary: You only need to change the protocol and port of one file (start_gateway.php), and nothing else needs to be changed.

3. Integration with ThinkPHP5.1 framework

(1) The server actively pushes messages to the client

Principle :

1. The TP5.1 framework project and the independent deployment of GatewayWorker do not interfere with each other

2. All business logic is requested from the website (websocket connected) page to TP5 through post/get. 1 Completed in the controller of the framework

3. GatewayWorker does not accept data sent from the client, that is, GatewayWorker does not process any business logic, and GatewayWorker is only used as a one-way push channel

4. Only when the TP5.1 framework needs to actively push data to the browser, the Gateway's API (GatewayClient) is called in the TP5.1 framework to complete the push

Specific implementation steps

1. The website page establishes a websocket connection with the GatewayWorker

ws = new WebSocket("ws://127.0.0.1:7272");
Copy after login

2. When the GatewayWorker finds that a page initiates a connection, it sends the client_id of the corresponding connection to the website page

Event.php content

public static function onConnect($client_id)
{
    $resData = [
        'type' => 'init',
        'client_id' => $client_id,
        'msg' => 'connect is success' // 初始化房间信息
    ];
    Gateway::sendToClient($client_id, json_encode($resData));
}
Copy after login

#index.html Content




    
    GatewayWorker的websocket连接


GatewayWorker的websocket连接

Copy after login

3. After the website page receives the client_id, it triggers an ajax request (index/chat_room/bind) to send the client_id to TP5.0 backend, bind method

/*
 * 用户登录后初始化以及绑定client_id
 */
public function bind()
{
    // 设置GatewayWorker服务的Register服务ip和端口,请根据实际情况改成实际值
    Gateway::$registerAddress = '127.0.0.1:1238';
    $uid = $this->userId;
    $group_id = $this->groupId;
    $client_id = request()->param('client_id');
    // client_id与uid绑定
    Gateway::bindUid($client_id, $uid);
    // 加入某个群组(可调用多次加入多个群组)
    Gateway::joinGroup($client_id, $group_id);
}
Copy after login

4. After receiving the client_id, the backend uses GatewayClient to call Gateway::bindUid($client_id, $uid) to compare the client_id with the current uid (user id or client unique identifier) ) binding. If there is a group or group sending function, you can also use Gateway::joinGroup($client_id, $group_id) to add the client_id to the corresponding group

Return value after successful connection

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

PS: The above return value is the json data returned after the GatewayWorker service successfully connects

5. All requests initiated by the page are directly post/get to the mvc framework for unified processing, including sending messages

Send messages through sendMessage (the server actively pushes messages to the client)

// mvc后端发消息 利用GatewayClient发送 Events.php
public function sendMessage()
{
    // stream_socket_client(): unable to connect to tcp://127.0.0.1:1236
    $uid = $this->userId;
    $group = $this->groupId;
    $message = json_encode([
      'type'=>'say',
      'msg'=>'Hello ThinkPHP5'
    ]);
    // 设置GatewayWorker服务的Register服务ip和端口,请根据实际情况改成实际值
    Gateway::$registerAddress = '127.0.0.1:1238';
    // 向任意uid的网站页面发送数据
    Gateway::sendToUid($uid, $message);
    // 向任意群组的网站页面发送数据,如果开启,则会向页面发送两条一样的消息
    //Gateway::sendToGroup($group, $message);
}
Copy after login

6. When the mvc framework needs to send data to a certain uid or a group during business processing, call it directly GatewayClient's interface Gateway::sendToUid Gateway::sendToGroup can be sent after waiting.

Access the sendMessage operation through the browser, test results

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

PS: The above message It is TP5.0 that sends write messages through GatewayClient\Gateway and has no direct relationship with the GatewayWorker service

The above is the server actively pushing messages to the client

Note the distinction:

1 , The server actively pushes messages to the client

2. The client pushes messages to the client

(2) The client pushes messages to the client

Modify the sending and receiving of messages from client to client. Modify Events.php of GatewayWorker below (developers only need to pay attention to this file)

public static function onConnect($client_id)
{
    $resData = [
        'type' => 'init',
        'client_id' => $client_id,
        'msg' => 'connect is success' // 初始化房间信息
    ];
    Gateway::sendToClient($client_id, json_encode($resData));
}
 
/**
 * 当客户端发来消息时触发
 * @param int $client_id 连接id
 * @param mixed $message 具体消息
 */
public static function onMessage($client_id, $message)
{
    // 服务端console输出
    //echo "msg : $message \r\n";
 
    // 解析数据
    $resData = json_decode($message, true);
    $type = $resData['type'];
    $roomId = $resData['roomId'];
    $userId = $resData['userId']; // 未登录,则传递一个随机
    $userName = $resData['userName']; // 未登录,则传递一个随机
    $content = isset($resData['content']) ? $resData['content'] : 'default content';
     
    //将时间全部置为服务器时间
    $serverTime = date('Y-m-d H:i:s', time());
 
    switch ($type) {
        case 'join':  // 用户进入直播间
            //将客户端加入到某一直播间
            Gateway::joinGroup($client_id, $roomId);
            $resData = [
                'type' => 'join',
                'roomId' => $roomId,
                'userName' => $userName,
                'msg' => "enters the Room", // 发送给客户端的消息,而不是聊天发送的内容
                'joinTime' => $serverTime // 加入时间                   
            ];
 
            // 广播给直播间内所有人,谁?什么时候?加入了那个房间?
            Gateway::sendToGroup($roomId, json_encode($resData));
            break;
        case 'say':  // 用户发表评论
            $resData = [
                'type' => 'say',
                'roomId' => $roomId,
                'userName' => $userName,
                'content' => $content,
                'commentTime' => $serverTime // 发表评论时间
            ];
            // 广播给直播间内所有人
            Gateway::sendToGroup($roomId, json_encode($resData));
            break;
        case 'pong':
            break; // 接收心跳
        default:
            //Gateway::sendToAll($client_id,$json_encode($resData));
            break;
    }
}
Copy after login

index.html Chat Room Page

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>GatewayWorker的websocket连接</title>
</head>
<body>
<h1>GatewayWorker的websocket连接</h1>
<div>
    websocket send content:<input type="text" style="height: 50px; width: 100%;" name="data" id="data">
    <p></p>
    <button id="submit" onclick="sub()">send info</button>
    <p></p>
    <div id="output"></div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.bootcss.com/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js"></script>
<script language="javascript" type="text/javascript">
    var wsUri = "ws://notes.env:7272/";
    var outputContent;
    var roomId = &#39;L06777&#39;;
    var userId = 4840043;
    var userName = &#39;Tinywan&#39; + Math.random();
 
    // 把当新链接的客户端加入到当前直播间,消息类型:{"type":"join","roomId":"1002","userId":"88","userName":"userName"}
    var joinContent = {
        "type": "join",
        "roomId": roomId,
        "userId": userId,
        "userName": userName
    };
 
    // 初始化页面操作
    function init() {
        outputContent = document.getElementById("output");
        initWebSocket();
    }
 
    function initWebSocket() {
        websocket = new ReconnectingWebSocket(wsUri);
        websocket.onopen = function (evt) {
            onOpen(evt)
        };
        websocket.onclose = function (evt) {
            onClose(evt)
        };
        websocket.onmessage = function (evt) {
            onMessage(evt)
        };
        websocket.onerror = function (evt) {
            onError(evt)
        };
    }
 
    function onOpen(evt) {
        console.log("CONNECTED");
    }
 
    // 接收数据
    function onMessage(evt) {
        var data = eval("(" + evt.data + ")");
        var type = data.type || &#39;&#39;;
        switch (type) {
            case &#39;init&#39;:
                // 把当新链接的客户端加入到当前直播间
                console.log(&#39;-------init--------&#39; + data);
                websocket.send(JSON.stringify(joinContent));
                writeToScreen(&#39;<span style="color: blue;">RESPONSE: &#39; + evt.data + &#39;</span>&#39;);
                break;
            case &#39;join&#39;:
                console.log(&#39;-------join--------&#39; + data);
                writeToScreen(
                    &#39;<span style="color: blue;"> &#39; + &#39; 新用户: &#39; + &#39;</span>&#39; +
                    &#39;<span style="color: red;"> &#39; + data.userName + &#39;</span>&#39; +
                    &#39;<span style="color: green;"> &#39; + data.joinTime + &#39;</span>&#39; +
                    &#39;<span style="color: black;"> &#39; + data.msg + &#39;</span>&#39;
                );
                break;
            case &#39;say&#39;:
                console.log(&#39;say======&#39; + data);
                writeToScreen(
                    &#39;<span style="color: blue;"> &#39; + &#39; Chat: &#39; + &#39;</span>&#39; +
                    &#39;<span style="color: red;"> &#39; + data.userName + &#39;</span>&#39; +
                    &#39;<span style="color: #D2691E;"> &#39; + data.commentTime + &#39;</span>&#39; +
                    &#39;<span style="color: black;"> &#39; + data.content + &#39;</span>&#39;
                );
                break;
            default :
                console.log(data);
                break;
        }
    }
 
    function onError(evt) {
        console.log(&#39;<span style="color: red;">ERROR:</span> &#39; + evt.data);
    }
 
    function onClose(evt) {
        console.log("DISCONNECTED");
    }
 
    function writeToScreen(message) {
        var pre = document.createElement("p");
        pre.style.wordWrap = "break-word";
        pre.innerHTML = message;
        outputContent.appendChild(pre);
    }
 
    function sub() {
        var text = document.getElementById(&#39;data&#39;).value;
        // {"type":"say",,"msg":"Welcome 111111111111Live Room"}
        var sayContent = {
            "type": "say",
            "roomId": roomId,
            "userId": userId,
            "userName": userName,
            "content": text
        };
        websocket.send(JSON.stringify(sayContent));
    }
    window.addEventListener("load", init, false);
</script>
</body>
</html> 
Copy after login

Restart the service

Test results

Case study of the combination of ThinkPHP5.1 framework and Workermans GatewayWorker framework

##Extension:

Can store messages In Redis, count the PV

of the live broadcast room through Redis

$redis = new \Redis;
$redis->connect(&#39;127.0.0.1&#39;,6379);
$key = "PV:ROOM:".$roomId;
$field = "ROOM_TOTAL_PV";
// 进入房间的人数增长,自增 ,增加PV统计
$redis->hIncrBy($key,$field,1);
Copy after login

相关推荐:《PHP教程

The above is the detailed content of Case study of the combination of ThinkPHP5.1 framework and Workerman's GatewayWorker framework. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:cnblogs.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template