Home  >  Article  >  PHP Framework  >  How workerman implements chat system

How workerman implements chat system

尚
Original
2019-12-12 14:03:123434browse

How workerman implements chat system

Install thinkphp5.1

composer create-project topthink/think=5.1.x-dev tp5andWorkerman

Install think-worker

composer require topthink/think-worker=2.0.*

Install Workerman directly

composer require workerman/workerman

(2) Let’s look at it first think-worker code

config/worker_server.php

Let’s take an example of a server broadcasting a message. A message is broadcast regularly every 10 seconds

'onWorkerStart'  => function ($worker) {
    \Workerman\Lib\Timer::add(10, function()use($worker){
        // 遍历当前进程所有的客户端连接,发送自定义消息
        foreach($worker->connections as $connection){
            $send['name'] = '系统信息';
            $send['content'] = '这是一个定时任务信息';
            $send['time'] = time();
            $connection->send(json_encode($send));
        }
    });}

But during onMessage, we cannot get the $worker object, so Unable to broadcast message.

'onMessage'      => function ($connection, $data) {
    $origin = json_decode($data,true);
    $send['name'] = '广播数据';
    $send['content'] = $origin['content'];
    $message = json_encode($send);

    foreach($worker->connections as $connection)
    {
        $connection->send($message);
    }}

Modify the code inside the framework: /vendor/topthink/think-worker/src/command/Server.php, mainly to add the onMessage method yourself

use() is to add the external Pass the variable to the function for internal use, or use global $worker

$worker = new Worker($socket, $context);$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    $send['name'] = '广播数据';
    $send['content'] = $origin['content'];
    $send['uid'] = $connection->uid;
    $message = json_encode($send);
    foreach($worker->connections as $connection)
    {
        $connection->send($message);
    }};

In this way, we can get the $worker object

$worker->onMessage = function ($connection, $data )use($worker) { ... }

(3) $connection is bound to uid

In fact, you have already seen that $worker->connections is obtained are the connections of all current users, and connections is one of the links.

Record websocket connection time:

$worker->onConnect = function ($connection) {
    $connection->login_time = time();};

Get websocket connection time:

$worker->onMessage = function ($connection, $data)use($worker) {
    $login_time = $connection->login_time;};

It can be seen that we can bind data to an attribute of the $connection connection, For example:

$connection->uid = $uid;

When the JavaScript side successfully connects to the websocket server, it immediately sends its uid to the server for binding:

var uid = 600;ws.onopen = function() {
    ws.send(JSON.stringify({bind:'yes',uid:uid}));};
$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    if(array_key_exists('bind',$origin)){
        $connection->uid = $origin['uid'];
    }};

(4) Unicast message, that is, customized sending

$worker->onMessage = function ($connection, $data)use($worker) {
    $origin = json_decode($data,true);
    $sendTo = $origin['sendto']; // 需要发送的对方的uid
    $content = $origin['content']; // 需要发送到对方的内容
    foreach($worker->connections as $connection)
    {
        if( $connection->uid == $sendTo){
            $connection->send($content);
        }
    }};

At this point, sending messages based on Workerman's custom object has been completed.

Since the php file is stored in composer, you only need to copy the file, put it in application/command, modify the namespace, and save it to your own project

(5) Storing chat records

Using Redis for caching has less impact on the server and basically does not affect the response time

1. Store chat records in Redis and use list storage

$message = json_decode($data,true); // $data为接收到的数据
$redis_instance = Cache::handler(); // TP5代码获取Cache实例
$redis_instance->lPush('message',json_encode($message,JSON_UNESCAPED_UNICODE));

2. In some cases, when the user first chats (or refreshes) the chat page, the last 10 records are displayed

$redis_instance = Cache::handler(); // TP5代码获取Cache实例
$worker->onConnect = function ($connection)use($redis_instance) {
    $length = $redis_instance->lLen('message');
    if($length > 0){
        $send['recently'] = array_reverse($redis_instance->lRange('message', 0, 10));
        $send['state'] = 200;
        $message = json_encode($send,JSON_UNESCAPED_UNICODE);
        $connection->send($message);
    }else{
        $send['state'] = 204;
        $send['recently'] = [];
        $send['msg'] = '暂无聊天记录';
        $message = json_encode($send,JSON_UNESCAPED_UNICODE);
        $connection->send($message);
    }
};

javascript handles when obtaining the recently recent chat records:

ws.onmessage = function(e) {
    var your = JSON.parse(e.data);
    if(your.recently){
        // 初次打开页面,渲染最近10条聊天记录
        $.each(your.recently,function(index,item){
            item = JSON.parse(item);
            // TODO:遍历渲染页面
        });
    }else{
        // 处理其他消息
        msglist.append(&#39;<li>&#39;+your.content+&#39;</li>&#39;);
    }
};

Recommended: workermantutorial

The above is the detailed content of How workerman implements chat system. For more information, please follow other related articles on the PHP Chinese website!

Statement:
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