Using WebSocket under thinkphp5

Posted by NTM on Mon, 21 Feb 2022 07:19:47 +0100

Recently, a project requirement is as follows: the software side will send a request to the server to obtain some information. Then process the acquired information and return the id of the information

Method 1: the software side calls the interface and requests once a minute.

The problem: if tens of thousands of people use the software at the same time, a large number of http requests will be generated, resulting in excessive load. Therefore, the second way needs to be considered.

Method 2: use WebSocket to make a long connection, which reduces a large number of requests.

Because the requirements for websocket are not high, we chose Workerman, which is also a encapsulated extension of thinkphp5, and can be downloaded directly.

Reference Manual: thinkphp5 1 and workerman Development Manual

Let's start:

Download using composer:

composer require topthink/think-worker

After downloading, there will be some files. Focus on the worker in config PHP and worker_server.php. These two are different listening configurations. I use worker_server.php

Its default configuration is like this

return [
    // Expand the configuration required by itself
    'protocol'       => 'websocket', // The protocol supports tcp udp unix http websocket text
    'host'           => '0.0.0.0', // Listening address
    'port'           => 2346, // Listening port
    'socket'         => 'hd.com:2346', // Full listening address
    'context'        => [], // socket context options
    'worker_class'   => '', // The custom Workerman service class name supports the definition of multiple services in an array
 
    // All configuration parameters of workerman are supported
    'name'           => 'thinkphp',
    'count'          => 4,
    'daemonize'      => false,
    'pidFile'        => Env::get('runtime_path') . 'worker.pid',
 
    // Support event callback
    // onWorkerStart
    'onWorkerStart'  => function ($worker) {
 
    },
    // onWorkerReload
    'onWorkerReload' => function ($worker) {
 
    },
    // onConnect
    'onConnect'      => function ($connection) {
 
    },
    // onMessage
    'onMessage'      => function ($connection, $data) {
        $connection->send('You did it');
    },
    // onClose
    'onClose'        => function ($connection) {
 
    },
    // onError
    'onError'        => function ($connection, $code, $msg) {
        echo "error [ $code ] $msg\n";
    },
];

At this time, you open the command line (cmd) and switch to the root directory of your project

E:\wamp64\www\hd\v2018>E:\wamp64\bin\php\php7.0.4\php.exe   think   worker:server

Because I didn't configure the environment variables of php, it's time to do this. At this time, you will see such a result, indicating that the service is started successfully

Open the chrome browser, press F12 to open the debugging Console, and enter in the Console column (or put the following code into the html page and run it with js)

// Suppose the server ip is 127.0.0.1
ws = new WebSocket("ws://127.0.0.1:2000");
ws.onopen = function() {
    alert("Connection successful");
};
ws.onmessage = function(e) {
    alert("Message received from the server:" + e.data);
};

 

This is the word "you succeeded".

The next step is the real development process.

Generally, we will create a service class (we must inherit} think\worker\Server), then set properties and add callback methods. This is a class I wrote

<?php
// +----------------------------------------------------------------------
// | websocket
// +----------------------------------------------------------------------
// | Author: myh
// +----------------------------------------------------------------------
 
namespace app\worker;
 
use think\worker\Server;
use app\common\api\BaseApi;
 
class Worker extends Server
{
    protected $socket = 'http://0.0.0.0:2346';
 
    public function onMessage($connection,$data)
    {
    	$data = explode('|', $data);
    	switch ($data[0]) {
    		case 'software_send_msg':
	            if(!isset($data[1]) || empty($data[1])) {
	            	$list = json_encode(['result'=>'error','message'=>'Parameter is null']);
	            }else{
	            	$account = $data[1];
		            $uid = BaseApi::findData(8,2,[['user_login','=',$account]],'id');
 
		            if($uid){
		                list($data) = BaseApi::getListOne(16,[['user_id','=',$uid],['status','=',0]]);//16-software_send_msg
		                if($data){
		                    $list = [];
		                    foreach ($data as $k => $v) {
		                        $list[$k]['id'] = $v['id'];
		                        $list[$k]['type'] = $v['type'];
		                        $list[$k]['msg']  = $v['msg'];
		                    }
		             
		                    $list = json_encode(['result'=>'success','data'=>json_encode($list)]);
		                }else{
		                    $list = json_encode(['result'=>'error', 'message'=>'Data is empty']);
		                }
		                
		            }else{
		                $list = json_encode(['result'=>'error', 'message'=>'The account information cannot be found']);
		            }
	            }
	            
    			break;
 
    		case 'software_send_msg2':
    			$msg = 3333;
    			break;
 
    		default:
    			$list = json_encode(['result'=>'error']);
    		break;
    	}
 
    	$connection->send($list);//Here the data is sent to the client
  
    }
 
  
}

At this time, we should pay attention to the worker_server.php to modify, delete the previous configuration, just add this

return [
    'worker_class'  =>  'app\worker\Worker',
];

controller:

public function ws()
{
        return $this->fetch(':ws');
}

Template:

<!DOCTYPE html>
<html xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
    <title>ThinkCMF WebSocket Demo</title>
 
    <script src="__STATIC__/js/jquery-2.0.3.min.js"></script>
</head>
<body>
 
<div id="app">
    Software simulation to get the latest news:
    <button class="get-msg">request</button>
 
    <div class="return-msg">
        
    </div>
</div>
 
<script>
 
$(document).on('click','.get-msg',function(){
    ws = new WebSocket("ws://127.0.0.1:2346");
    
    //Organizational parameters
    var param = new Array();
    param.push('software_send_msg');
    param.push('wydyhdzh');
 
    ws.onopen = function() {
        ws.send(param.join('|'));//Send back information to the server
    };
 
    ws.onmessage = function(e) {//Server return information
        var data = JSON.parse(e.data);
    
        if(data.result == 'success'){
            var list = JSON.parse(data.data);
            $('.return-msg').html(data.data);
        }
    };
})
    
</script>
</body>
</html>

This is the whole process!!!  

Topics: network Network Protocol websocket