Think tools

Time:2020-10-31

Official website document

Thinkphpp6 documentation
https://www.kancloud.cn/manua…

Swote document
https://wiki.swoole.com/#/

Think tool document
https://www.kancloud.cn/manua…

install

composer require topthink/think-swoole

command line

php think swoole [start|stop|reload|restart]

Service startup

When you’re on the command linephp think swooleAfter the next execution, an HTTP server will be started, which can directly access the current application

'server'     => [
    'host'      => env('SWOOLE_ Host ','0.0.0.0'), // listening address
    'port'      => env('SWOOLE_ Port ', 9501), // listening port
    'mode'      => SWOOLE_ Process, // the default running mode is swotle_ PROCESS
    'sock_ type' => SWOOLE_ SOCK_ TCP, // the sock type is swoole by default_ SOCK_ TCP
    'options'   => [
        //After the service is started, the process ID stores the file
        'pid_file'              => runtime_path() . 'swoole.pid',
        //The log file of swote
        'log_file'              => runtime_path() . 'swoole.log',
        //The daemons mode is set to true to run in the background
        'daemonize'             => false,
        //Set the number of reactor threads to start
        'reactor_num'           => swoole_cpu_num(),
        //Set the number of worker processes started
        'worker_num'            => swoole_cpu_num(),
        //Configure the number of task processes
        'task_worker_num'       => swoole_cpu_num(),
        //To enable static file request processing, you need to cooperate with document_ root
        'enable_static_handler' => true,
        //Static file root
        'document_root'         => root_path('public'),
        //Set the maximum packet size in bytes
        'package_max_length'    => 20 * 1024 * 1024,
        //Configure send output buffer memory size
        'buffer_output_size'    => 10 * 1024 * 1024,
        //Maximum number of client connections allowed
        'socket_buffer_size'    => 128 * 1024 * 1024,
    ],
],

Hot update

During the operation of the droole server, PHP files run in memory, so that repeated reading of disk, repeated interpretation and compilation of PHP can be avoided, so as to achieve the highest performance. Therefore, the service needs to be restarted to modify the code

The think tool extension provides the function of heating update. It will restart automatically when the related files are updated. It is not necessary to restart manually, so it is convenient for development and debugging

Under the condition that you do not need to modify the production environment, it is recommended that the file be updated without error

.envIt’s set insideAPP_DEBUG = trueHot update is enabled by default

'hot_update' => [
    'enable'  => env('APP_DEBUG', false),
    'name'    => ['*.php'],
    'include' => [app_path()],
    'exclude' => [],
],

Parameter description

parameter explain
enable Do you want to turn on hot update
name What types of file changes are monitored
include Which directory is monitored for file changes
exclude Exclude directory

websocket

Let’s start with an official example

$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
    echo "server: handshake success with fd{$request->fd}\n";
});
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
    echo "receive from {$frame->fd}:{$frame->data}\n";
    $server->push($frame->fd, "this is server");
});
$server->on('close', function ($ser, $fd) {
    echo "client {$fd} closed\n";
});
$server->start();

Open the websocket function of think spool\config\swoole.php

'websocket'  => [
    'enable'        => true,
],

Create three events

php think make:listener SwWsConnect
php think make:listener SwWsClose
php think make:listener SwWsMessage

Then write these three events to the event monitor. There are two files below that can be modified. Please select one from two

Event binding with thinkphpp6app\event.php

'listen'    => [
        ........
        //Listen for links
        'swoole.websocket.Connect' => [
            \app\listener\SwWsConnect::class
        ],
        //Close connection
        'swoole.websocket.Close' => [
            \app\listener\SwWsClose::class
        ],
        //Sending message scenario
        'swoole.websocket.Message' => [
            \app\listener\SwWsMessage::class
        ]
    ],

Think tool event bindingconfig\swoole.php

'listen'        => [
    'connect'=>\app\listener\SwWsConnect::class,
    'close'=>\app\listener\SwWsClose::class,
    'message'=> \app\listener\SwWsMessage::class
],

How to choose is saved inconfig\swoole.phpstillapp\event.phpWhat about the configuration?

First of all, let’s make sure that there are several real-time communications in our project,

If there is only a real-time communication, personal suggestions are saved inconfig\swoole.php

If there are multiple real-time communications, save them in theapp\event.php

The key value must beswoole.websocket . event namefor exampleswoole.websocket.Message

Start writing method in event

Connection eventsapp\listener\SwWsConnect.php

public function handle($event, \think\swoole\websocket $ws)
{
    //Get the FD of the current sender
    $fd = $ws->getSender();
    echo "server: handshake success with fd{$fd}\n";
}

Close eventapp\listener\SwWsClose.php


public function handle($event, \think\swoole\websocket $ws)
{
    $fd = $ws->getSender();
    echo "client {$fd} closed\n";
}

Message eventapp\listener\SwWsMessage.php

public function handle($event, \think\swoole\websocket $ws)
{
    $fd = $ws->getSender();
    $data = json_encode($event);
    echo "receive from {$fd}:{$data}\n";
    $ws->emit("this is server", $fd);
}

start-upphp think swooleTest

Summary of websocket method in think spool

//Send yourself a message
$ws->emit("this is server", $ws->getSender());
//Send a message to a specified FD
$ws->to($to)->emit("messagecallback",$data);
//Send a message to a specified number of people
$ws->to([1,2,3])->emit("messagecallback",$data);
//Send to all (not including yourself)
$ws->broadcast()->emit("messagecallback",$data);
//Simulate formfd sending message to TOFD
$ws->setSender($formfd)->to($tofd)->emit("messagecallback",$data);

Note: use in multiple real-time communication scenariosemit

The first parameter passes in the incoming event name callback, for examplemessagecallback

If you don’t have a way to do this in think tool

$sw = app('swoole.server');
$sw = app("think\swoole\Manager")->getServer();
//Choose one of the above two

$ES = $SW - > isestablished ($FD); // check whether the connection is a valid websocket client connection
var_dump($es);

Realization of room in chat room

Front end document referencehtml\room.htmlorhtml\room-socket-io.html

php think make:listener SwRoomJoin
php think make:listener SwRoomLeave
php think make:listener SwRoomMessage

Event binding

//Join the room
'swoole.websocket.RoomJoin' => [
    \app\listener\SwRoomJoin::class
],
//Leave the room
'swoole.websocket.Roomleave' => [
    \app\listener\SwRoomLeave::class
],
//Send a message in the room
'swoole.websocket.RoomMessage' => [
    \app\listener\SwRoomMessage::class
]

Add room logic

public function handle($event, \think\swoole\websocket $ws, \think\swoole\websocket\room $room)
{
    $fd = $ws->getSender();
    //Room of client
    $roomid = $event['room'];
    //Get the clients under the specified room
    $roomfds = $room->getClients($roomid);
    //Judge whether the room has its own or not. If it has its own, you don't need to send the notice again
    if (in_array($fd, $roomfds)) {
        $WS - > to ($roomfds) - > emit ("roomjoincallback", "room {$roomid} has been added");
        return;
    }
    //Join the room
    $ws->join($roomid);
    $WS - > to ($roomfds) - > emit ("roomjoincallback", "{$FD} joined the room {$roomid} successfully");
}

Leave room logic

public function handle($event, \think\swoole\websocket $ws, \think\swoole\websocket\Room $room)
{
    $roomid = $event['room'];
    $fd = $ws->getSender();
    $roomfds = $room->getClients($roomid);
    if (!in_array($fd, $roomfds)) {
        $WS - > emit ("roomleave callback", "{$FD} is not in {$roomid} room, how to leave ~");
        return;
    }
    //Leave the room
    $ws->leave($roomid);
    //Get which clients are joined by the current client
    $rooms = $room->getRooms($fd);
    $WS - > to ($roomfds) - > emit ("roomleave callback", "{$FD} has left ~ ~);
}

Post chat logic in the room

public function handle($event, \think\swoole\websocket $ws, \think\swoole\websocket\room $room)
    {
        //
        $roomid = $event['room'];
        $text = $event['text'];
        $fd = $ws->getSender();
        $roomfds = $room->getClients($roomid);
        if (!in_array($fd, $roomfds)) {
            $WS - > emit ("room message callback", "{$FD} is not in {$roomid} room, unable to enter post chat ~");
            return;
        }
        $ws->to($roomfds)->emit("roommessagecallback",  $text);
    }

event subscriptions

php think make:listener SwSubscribe

applistenerSwSubscribe.php

<?php
declare (strict_types = 1);

namespace app\listener;

class SwSubscribe
{
    protected $ws = null;

    // public function __construct()
    // {
    //     $this->ws = app('think\swoole\Websocket');
    // }

    public function __construct(\think\Container $c)
    {
        $this->ws = $c->make(\think\swoole\Websocket::class);
    }
    
    public function onConnect()
    {
        $fd = $this->ws->getSender();
        echo "server: handshake success with fd{$fd}\n";
    }
    public function onClose()
    {
        $fd = $this->ws->getSender();
        echo "client {$fd} closed\n";
    }
    public function onMessage($event)
    {
        $fd = $this->ws->getSender();
        var_dump($event);
        echo "server: handshake success with fd{$fd}\n";
        $this->ws->emit("this is server", $fd);
    }
}

It’s a little similar to changing the original swote code into object-oriented code to take effectconfig\swoole.phpInsubscribejoin\app\listener\SwSubscribe::class

'subscribe'     => [
    \app\listener\SwSubscribe::class
],

stayapp\event.phpIn the fileswoole.websocket.Connectamount toapp\listener\SwSubscribe.phpIn the fileonConnectFunction. If it exists at the same time, it will send more than 2 messages to the client

Task delivery

https://wiki.swoole.com/#/sta…

Build event

php think make:listener SwSendEmailTask

Write the method of sending mailapp\listener\SwSendEmailTask.php

public function handle($event)
{
    var_dump($event);
    //
    Echo "development send mail". Time();
    sleep(3);
    Echo "end sending mail". Time();
}

Registration eventsapp\event.php

'swoole.task'=>[
    \app\listener\SwSendEmailTask::class
],

Post task in controller

public function doRegister()
{
    $server = app('swoole.server');
    $server->task(\app\listener\SwSendEmailTask::class);
    Return "registered successfully.";
}

public function doRegister(\think\swoole\Manager $manager)
{
    $server = $manager->getServer();
    $server->task(\app\listener\SwSendEmailTask::class);
    Return "registered successfully.";
}
public function doRegister(\Swoole\Server $server)
{
    $server->task(\app\listener\SwSendEmailTask::class);
    Return "registered successfully.";
}

Three kinds of acquisition\Swoole\ServerChoose one of them

There is also an event in droole calledfinishIts function is to return the results of asynchronous tasks, which is handled in think tool

Defines an event that sends the result of an asynchronous task sending mail

php think make:listener SwSendEmailFinish

Registration eventsapp\event.php

'swoole.finish'=>[
    \app\listener\SwSendEmailFinish::class
],

Call in task task

public function handle($event)
{
    var_dump($event);
    //
    Echo "development send mail". Time();
    sleep(3);
    Echo "end sending mail". Time();
    $event->finish(\app\listener\SwSendEmailFinish::class);
}

High performance shared memory table

https://wiki.swoole.com/#/mem…

The pre-determined structure is operating data (native swote operation)

$table = new Swoole\Table(1024);
//Create table
$table->column("id", Swoole\Table::TYPE_INT);
$table->column("name", Swoole\Table::TYPE_STRING);
$table->column("money", Swoole\Table::TYPE_FLOAT);
$table->create();

//Add data
$table->set("zq", [
    'id' => 1,
    'name' => "zhiqiang",
    'money' => 100,
]);
//Get a row of data
$table->get("zq");
//Modify data
//Field increment
$table->incr("zq","money",2);
//Decline
$table->decr("zq","money",2);
//Returns the number of entries in the table.
$table->count();
//Traversing data in table
foreach($table as $item){
    var_dump($item);
}

Operations in think tool

Initialize the table structure firstconfig\swoole.php

    'tables'     => [
        'user'=>[
            'size'=>1024,
            'columns'=>[
                [
                    'name'=>'id',
                    'type'=>\Swoole\Table::TYPE_INT
                ],
                [
                    'name'=>'name',
                    'type'=>\Swoole\Table::TYPE_STRING,
                    'size'=>32
                ],
                [
                    'name'=>'money',
                    'type'=>\Swoole\Table::TYPE_FLOAT
                ],

            ],
        ],
    ],

Operation data

$table =  app('swoole.table.user');
$table->set("zq", [
    'id' => 1,
    'name' => "zhiqiang",
    'money' => 100
]);
//Get a row of data
$table->get("zq");
//Modify data
//Field increment
$table->incr("zq", "money", 2);
//Decline
$table->decr("zq", "money", 2);
//Returns the number of entries in the table.
$table->count();
//Traversing data in table
foreach ($table as $item) {
var_dump($item);
}
//Check whether a key exists in the table.
$table->exist('zq');
//Get the actual occupied memory size in bytes
$table->momorySize();

RPC

RPC (remote procedure call): remote procedure call, it is a kind of thought that requests the service from the remote computer program through the network, and does not need to understand the underlying network technology.

Details:https://developer.51cto.com/a…

  • Solve the problem of calling between services in distributed system.
  • When calling a remote call, it should be as convenient as the local call, so that the caller can not perceive the logic of the remote call.
  • Node role description:
  • Server: service provider of exposing service
  • Client: service consumer calling remote service
  • Registry: a registry for service registration and discovery

RPC function realized by think tool

Server side

Interface definitionapp/rpc/interfaces/UserInterface.php

<?php
namespace app\rpc\interfaces;
interface UserInterface
{
    public function create();
    public function find(int $id);
}

Implementation interfaceapp/rpc/services/UserService.php

<?php
namespace app\rpc\services;
use app\rpc\interfaces\UserInterface;
class UserService implements UserInterface
{
    public function create()
    {
        // TODO: Implement create() method.
        return "service create success";
    }
    public function find(int $id)
    {
        // TODO: Implement find() method.
        Return $ID. "query data traversal";
    }
}

Register RPC serviceconfig/swoole.php

'rpc'        => [
        'server' => [
            //Start RPC service
            'enable'   => true,
            //RPC port
            'port'     => 9000,
            'services' => [
                //Registration services
                \app\rpc\services\UserService::class
            ],
        ],
        //If you fill in, you can also call other servers
        'client' => [
        ],
    ],

Start server

php think swoole start /  php think swoole:rpc

client

'rpc'        => [
        'server' => [
        ],
        'client' => [
            'tp6'=>[
                //IP address of server
                'host'=>'127.0.0.1',
                //The port corresponding to the server
                'port'=>'9000'
            ]
            //More servers
        ],
    ],

functionphp think rpc:interfaceGenerate RPC interface fileapp\rpc.php

<?php
/**
 * This file is auto-generated.
 */
declare(strict_types=1);
namespace rpc\contract\tp6;
interface UserInterface
{
    public function create();
    public function find(int $id);
}
return ['tp6' => ['rpc\contract\tp6\UserInterface']];

Call in controller

    public function index(\rpc\contract\tp6\UserInterface $user)
    {
        //
        $user->find(1);
//        $user->create();
    }

Timed tasks

In the think Tool 2.0 version, the user-defined scheduled task configuration is still supported. Please refer tohttps://github.com/top-think/…

It is not supported in 3.0. Here we introduce a general command line to start the timing task

php think make:command SwooleTimer

Load command lineconfig/console.php

'commands' => [
    'swooletimer'=>app\command\SwooleTimer::class
    ...........
],

Writing command scriptsapp/command/SwooleTimer.php

<?php
declare (strict_types = 1);

namespace app\command;

use think\console\Command;
use think\console\input\Argument;


class SwooleTimer extends Command
{
    protected function configure()
    {
        //Instruction configuration
        $this->setName('app\command\swooletimer')
            ->addArgument('action', Argument::OPTIONAL, "start | stop", 'start')
            ->setDescription('Swoole Timer for ThinkPHP');
    }


    public function handle()
    {
        $action = $this->input->getArgument('action');
        if (in_array($action, ['start','stopall'])) {
            $this->app->invokeMethod([$this, $action], [], true);
        } else {
            $this->output->writeln("<error>Invalid argument action:{$action}, Expected start</error>");
        }
    }

    /**
     *Start the scheduled task. The main task plan is written here
     */
    protected function start()
    {
        // https://wiki.swoole.com/#/timer
        $timer_id=swoole_timer_tick(2000,function (){
            Echo "2 s loop performs what needs to be done". Time() ".";
        });
        $this->output->writeln("Swoole Timer_id:{$timer_id} ");
    }

    /**
     *Clear all scheduled tasks
     */
    protected  function stop(){
        swoole_timer_clear_all();
        $this->output->writeln("Swoole Timer  clear all ok");
    }
}