ThinkPHP5 utilizes WebSocket to achieve site-wide announcement push

Original link: https://5ime.cn/ws-notify.html

WebSocket is a protocol for full-duplex communication over a single TCP connection, allowing the server to actively push data to the client.

Recently, I was developing the公告实时推送in MoeCTF . I originally wanted to implement it through轮询, but after thinking about轮询, the client actively sends requests to the server. If a single user feels okay, but if there are too many online users If the request is made in a轮询manner, it will not only cause a large number of useless requests to cause excessive load.

So I plan to use WebSocket to make a long connection and reduce requests. Since there are not too many requirements for WebSocket , the WorkerMan developed based on GatewayWorker is directly selected.

Install

ThinkPHP5 can only install version 2.*

 1
 composer require topthink/think-worker=2.0.*

Events

Modify the onConnect and onMessage methods in vendor/topthink/think-worker/src/Events.php

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
 // 当有客户端连接时,将client_id返回,让mvc框架判断当前uid并执行绑定
public static function onConnect ( $client_id )
{
Gateway :: sendToClient ( $client_id , json_encode ( array (
'type' => 'init' ,
'client_id' => $client_id
)));
}

// GatewayWorker建议不做任何业务逻辑,onMessage留空即可
public static function onMessage ( $client_id , $message )
{

}

run

Note that you need to restart every time you modify the configuration of WorkerMan

 1
 php think worker:server

image-20221030184852357

controller

When the server receives a connection request, it determines whether the user is logged in. If already logged in, add the client_id to the group All

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
twenty one
twenty two
twenty three
twenty four
25
26
27
28
29
30
31
32
 <?php
namespace app \ index \ controller ;
use GatewayWorker \ Lib \ Gateway ;
use think \ facade \ Session ;
use think \ Controller ;

class Push extends controller
{
public function initialize ( )
{
parent :: initialize ();
if (! Session :: has ( 'uid' ) {
returnJsonData ( 201 , 'Please login first' )-> send ();
exit ;
}
}

public function index ( $data ) {
$data = [
'type' => 'notify' ,
'msg' => input ( 'msg' ),
];
Gateway :: sendToGroup ( 'All' , json_encode ( $data ));
}

public function notify ( )
{
Gateway :: $registerAddress = '127.0.0.1:1236' ;
$client_id = $_POST [ 'client_id' ];
Gateway :: joinGroup ( $client_id , 'All' );
}
}

User Interface

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 ws = new WebSocket ( "ws://127.0.0.1:2348" );
ws. onmessage = function ( e ) {
var data = eval ( "(" + e. data + ")" );
var type = data. type || "" ;
switch (type) {
case "init" :
$. post (
"/api/v1/notify" ,
{ client_id : data. client_id },
function ( data ) {},
"json"
);
break ;
case "notify" :
console . log ( 'notify:' + data);
break ;
default :
console . log (data);
}
};

Effect

The data requested by the administrator through the push method will be pushed to all logged in users.

image-20221030184920941

This article is reprinted from: https://5ime.cn/ws-notify.html
This site is for inclusion only, and the copyright belongs to the original author.