How to use Workman to make a chat room

Keywords: PHP socket Javascript Windows

1: First, let's talk about the installation of thinkphp+workerman.

Install thinkp5.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 first look at the code of think worker

  • 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 scheduled 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);

    }

}

Tried all kinds of methods, it seems that they can't

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

    // You can't get the $worker object

    // ... omit code

}

So we can only discard the think worker framework encapsulated by thinkphp. We have to write it ourselves (or modify the internal code of the framework)

Modify the internal code of the framework: / vendor / topthink / think worker / SRC / command / server.php, mainly adding the onMessage method itself

use() is to pass external variables 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'] = '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, as you've seen for a long time, $worker - > connections obtains the connections of all current users, and connections is one of them.

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 bind data to a property of the $connection connection connection, for example:

$connection->uid = $uid;

When the JavaScript end successfully connects to the websocket server, it immediately sends its uid to the server 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 send message, i.e. custom send

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

    $origin = json_decode($data,true);

    $sendTo = $origin['sendto']; // 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, you have finished sending messages based on workman's custom objects.

Because 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 in your own project

5: Compare swoole

1. workman can run on windows, but swoole can't.

2. workman: $worker - > connections gets all connections, $connection - > id gets its own connection id; swoole: $server - > connections gets all connections, $connection - > FD gets its own connection id.

3. When workman starts, the onWorkerStart method is executed, and the timer can be written into it; swoole uses WorkerStart to start the timer.

In terms of chat room or timer, workman is more convenient.

I hope that the above content can help you. Many PHPer will encounter some problems and bottlenecks when they are advanced. There is no sense of direction when they write too much business code. I don't know where to start to improve. I have collated some information about this, including but not limited to: distributed architecture, high scalability, high performance, high concurrency, server performance tuning, TP6, laravel, YII2, Redis, Swoo Le, Swoft, Kafka, Mysql optimization, shell script, Docker, microservice, Nginx and other advanced dry goods can be shared to you for free, and those needed can join my official group Click here.

Posted by richmlpdx on Thu, 26 Dec 2019 05:40:52 -0800