How to make a chat room with workman

Time:2020-7-30

1: First of all, let’s talk about the installation of ThinkPHP + worker man.

Install thinkphpp5.1

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

Install think worker

My official group click here.

composer require workerman/workerman

2: Let’s look at the code for think worker first

  • config/worker_server.php
  • Let’s start with an example of a server broadcasting a message every 10 seconds
'onWorkerStart'  => function ($worker) {

    \Workerman\Lib\Timer::add(10, function()use($worker){

        //Traverse all client connections of the current process and send custom messages

        foreach($worker->connections as $connection){

            $send ['name '] ='system information';

            $send ['content '] ='This is a timed task information';

            $send['time'] = time();

            $connection->send(json_encode($send));

        }

    });

}

But in onmessage, we can’t get the $worker object, so we can’t broadcast the message.

'onMessage'      => function ($connection, $data) {

    $origin = json_decode($data,true);

    $send ['name '] ='broadcast data';

    $send['content'] = $origin['content'];

    $message = json_encode($send);

 

    foreach($worker->connections as $connection)

    {

        $connection->send($message);

    }

}

All kinds of methods have been tried, but none seems to work

'onMessage'      => function ($connection, $data)use($worker) {

    //This will not get the $worker object

    //... omit the code

}

So we can only discard the think worker framework encapsulated by ThinkPHP and write it by ourselves (or modify the internal code of the framework)

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

Use () is to pass external variables to the function for internal use, or useglobal $worker

$worker = new Worker($socket, $context);

 

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

    $origin = json_decode($data,true);

    $send ['name '] ='broadcast data';

    $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 binding UID

In fact, you have already seen that $worker > connections gets 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;

};

From this, we can see that we can bind the data to a property 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 side for binding:

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

    $origin = json_decode($data,true);

    if(array_key_exists('bind',$origin)){

        $connection->uid = $origin['uid'];

    }

};

4: Unicast sending message, that is, custom sending

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

    $origin = json_decode($data,true);

    $SendTo = $origin ['sendto ']; // the uid of the other party to be sent

    $content = $origin ['content ']; // content to be sent to the other party

    foreach($worker->connections as $connection)

    {

        if( $connection->uid == $sendTo){

            $connection->send($content);

        }

    }

};

At this point, we have finished sending messages based on the workman custom object.

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

5: Contrast with swote

1. Workman can run in Windows system, but swote can’t.

2. Workman: $worker – > connections gets all connections; $connection > ID gets its own connection ID; spoole: $server > connections gets all connections; $connection – > FD gets its own connection ID.

3. When the workman is started, the onworkerstart method is executed, and the timer can be written into it; the Toole uses the workerstart to start the timer.

Just for chat rooms or timers, workman is more convenient.

The above contents hope to help you. Many PHPer will encounter some problems and bottlenecks when they are advanced. There is no sense of direction when writing too much business code, and I don’t know where to start to improve. For this, I have sorted out some materials, including but not limited to: distributed architecture, high scalability, high performance, high concurrency, server performance tuning, tp6, laravel, yii2, redis, and Swoo Le, swoft, Kafka, MySQL optimization, shell script, docker, microservice, nginx and other knowledge points. Advanced dry goods that you need can be shared with you free of charge. If you need, you can join my official group. Click here.