• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

thinkswoole使用

php 搞代码 3年前 (2022-03-01) 15次浏览 已收录 0个评论
文章目录[隐藏]

官网文档

thinkphp6文档
https://www.kancloud.cn/manua…

swoole文档
https://wiki.swoole.com/#/

think-swoole文档
https://www.kancloud.cn/manua…

装置

composer require topthink/think-swoole

命令行

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

服务启动

当你在命令行php think swoole下执行实现之后就会启动一个HTTP Server,能够间接拜访以后的利用

'server'     => [
    'host'      => env('SWOOLE_HOST', '0.0.0.0'), // 监听地址
    'port'      => env('SWOOLE_PORT', 9501), // 监听端口
    'mode'      => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS
    'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP
    'options'   => [
        // 服务启动后,过程ID寄存文件
        'pid_file'              => runtime_path() . 'swoole.pid',
        // swoole 的日志文件
        'log_file'              => runtime_path() . 'swoole.log',
        // 守护过程模式设置 true 后盾运行
        'daemonize'             => false,
        // 设置启动的reactor线程数
        'reactor_num'           => swoole_cpu_num(),
        // 设置启动的worker过程数
        'worker_num'            => swoole_cpu_num(),
        //配置Task过程的数量
        'task_worker_num'       => swoole_cpu_num(),
        //开启动态文件申请解决,需配合document_root
        'enable_static_handler' => true,
        //动态文件根目录
        'document_root'         => root_path('public'),
        // 设置最大数据包尺寸,单位字节
        'package_max_length'    => 20 * 1024 * 1024,
        //配置发送输入缓冲区内存尺寸
        'buffer_output_size'    => 10 * 1024 * 1024,
        //设置客户端连贯最大容许占用的内存数量
        'socket_buffer_size'    => 128 * 1024 * 1024,
    ],
],

热更新

swoole服务器运行过程中php文件是常驻内存运行,这样就能够防止反复的读取磁盘,反复的解释编译php,以便达到最高的性能,所以批改代码须要重启服务

think-swoole扩大提供热更新性能,在检测相干文件有更新会主动重启,不在须要手动实现重启,不便开发调试

生产环境下不倡议开始文件监控,性能损耗,失常状况下你所批改的文件须要确认无误能力进行更新部署

.env外面设置APP_DEBUG = true会默认开启热更新

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

参数阐明

参数 阐明
enable 是否开启热更新
name 监听哪些类型的文件变动
include 监听哪些目录下的文件变动
exclude 排除目录

websocket

先来一个官网的例子

$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();

开启think-swoole的websocket性能 \config\swoole.php

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

创立三个事件

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

而后将这三个事件写到到事件监听中,别离有以下2中文件能够批改形式,留神二选一

thinkphp6自带的事件绑定app\event.php

    'listen'    => [
        ........
        // 监听链接
        'swoole.websocket.Connect' => [
            \app\listener\SwWsConnect::class
        ],
        //敞开连贯
        'swoole.websocket.Close' => [
            \app\listener\SwWsClose::class
        ],
        //发送音讯场景
        'swoole.websocket.Message' => [
            \app\listener\SwWsMessage::class
        ]
    ],

think-swoole事件绑定config\swoole.php

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

怎么抉择是保留在config\swoole.php还是app\event.php配置中呢?

首先咱们 咱们确定一下咱们这个我的项目中存在有几个实时通信,

如果只是存在一个实时通信 集体倡议 保留在config\swoole.php

如果是存在多个实时通信,就保留在app\event.php

key值 必须是swoole.websocket.事件名称 例如 swoole.websocket.Message

开始写事件中中办法

连贯事件app\listener\SwWsConnect.php

public function handle($event, \think\swoole\websocket $ws)
{
    // 获取以后发送者的fd
    $fd = $ws->getSender();
    echo "server: handshake success with fd{$fd}\n";
}

敞开事件app\listener\SwWsClose.php

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

message事件app\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);
}

启动php think swoole进行测试

think-swoole中的websocket办法总结

//给本人发消息
$ws->emit("this is server", $ws->getSender());
//给指定一个fd发消息
$ws->to($to)->emit("messagecallback",$data);
//给指定多集体发消息
$ws->to([1,2,3])->emit("messagecallback",$data);
//发送给所有的(不蕴含本人)
$ws->broadcast()->emit("messagecallback",$data);
//模仿formfd 给tofd 发送音讯
$ws->setSender($formfd)->to($tofd)->emit("messagecallback",$data);

留神:在多个实时通信场景下应用 emit

第一个参数传入 传入 事件名称callback 例如 messagecallback

如果你发现你think-swoole中有些没有swoole中的办法能够这么干

$sw = app('swoole.server');
$sw = app("think\swoole\Manager")->getServer();
//以上二选一

$es = $sw->isEstablished($fd); //查看连贯是否为无效的WebSocket客户端连贯
var_dump($es);

聊天室room实现

前端文件参考 html\room.htmlhtml\room-socket-io.html

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

事件绑定

// 退出房间
'swoole.websocket.RoomJoin' => [
    \app\listener\SwRoomJoin::class
],
// 来到房间
'swoole.websocket.Roomleave' => [
    \app\listener\SwRoomLeave::class
],
// 在房间发消息
'swoole.websocket.RoomMessage' => [
    \app\listener\SwRoomMessage::class
]

退出房间逻辑

public function handle($event, \think\swoole\websocket $ws, \think\swoole\websocket\room $room)
{
    $fd = $ws->getSender();
    //客户端如果定的room
    $roomid = $event['room'];
    //获取指定房间下有哪些客户端
    $roomfds = $room->getClients($roomid);
    // 判断这个房间有没有本人 如果有本人就不须要再次发送告诉
    if (in_array($fd, $roomfds)) {
        $ws->to($roomfds)->emit("roomjoincallback", "房间{$roomid}已退出");
        return;
    }
    //退出房间
    $ws->join($roomid);
    $ws->to($roomfds)->emit("roomjoincallback", "{$fd}退出房间{$roomid}胜利");
}

来到房间逻辑

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("roomleavecallback", "{$fd}不在{$roomid}房间内,怎么来到~");
        return;
    }
    //来到房间
    $ws->leave($roomid);
    //获取以后客户端退出了哪些客户端
    $rooms = $room->getRooms($fd);
    $ws->to($roomfds)->emit("roomleavecallback", "{$fd}已来到了~~");
}

在房间公布聊天逻辑

    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("roommessagecallback", "{$fd}不在{$roomid}房间内,无奈进入公布聊天~");
            return;
        }
        $ws->to($roomfds)->emit("roommessagecallback",  $text);
    }

事件订阅

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);
    }
}

有点相似 将原生的swoole代码改成面向对象代码,失效办法 config\swoole.php中在subscribe 退出\app\listener\SwSubscribe::class

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

app\event.php文件中的 swoole.websocket.Connect 相当于 app\listener\SwSubscribe.php文件中的onConnect函数。如果同时存在的存在的话,就会向客户端发送2次以上的音讯

Task工作投递

https://wiki.swoole.com/#/sta&#8230;

生成事件

php think make:listener SwSendEmailTask

编写发送邮件办法app\listener\SwSendEmailTask.php

public function handle($event)
{
    var_dump($event);
    //
    echo "开发发送邮件".time();
    sleep(3);
    echo "完结发送邮件".time();
}  

注册事件app\event.php

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

在控制器中投递工作

public function doRegister()
{
    $server = app('swoole.server');
    $server->task(\app\listener\SwSendEmailTask::class);
    return "注册胜利";
}

public function doRegister(\think\swoole\Manager $manager)
{
    $server = $manager->getServer();
    $server->task(\app\listener\SwSendEmailTask::class);
    return "注册胜利";
}
public function doRegister(\Swoole\Server $server)
{
    $server->task(\app\listener\SwSendEmailTask::class);
    return "注册胜利";
}

三种获取\Swoole\Server,任意选其一

在swoole中还有一个事件叫finish,它的作用就是把异步工作的后果返回,在think-swool是这么解决的

定义一个发送邮件异步工作处理结果的事件

php think make:listener SwSendEmailFinish

注册事件app\event.php

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

在task工作中调用

public function handle($event)
{
    var_dump($event);
    //
    echo "开发发送邮件".time();
    sleep(3);
    echo "完结发送邮件".time();
    $event->finish(\app\listener\SwSendEmailFinish::class);
} 

高性能共享内存 Table

https://wiki.swoole.com/#/mem&#8230;

先定结构在进行操作数据(原生swoole操作)

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

//增加数据
$table->set("zq", [
    'id' => 1,
    'name' => "zhiqiang",
    'money' => 100,
]);
//获取一行数据
$table->get("zq");
// 批改数据
// 字段递增
$table->incr("zq","money",2);
//递加
$table->decr("zq","money",2);
// 返回 table 中存在的条目数。
$table->count();
//遍历table中的数据
foreach($table as $item){
    var_dump($item);
}

think-swoole中的操作

先对table表构造进行初始化config\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
                ],

            ],
        ],
    ],

操作数据

$table =  app('swoole.table.user');
$table->set("zq", [
    'id' => 1,
    'name' => "zhiqiang",
    'money' => 100
]);
//获取一行数据
$table->get("zq");
// 批改数据
// 字段递增
$table->incr("zq", "money", 2);
//递加
$table->decr("zq", "money", 2);
// 返回 table 中存在的条目数。
$table->count();
//遍历table中的数据
foreach ($table as $item) {
var_dump($item);
}
// 查看 table 中是否存在某一个 key。
$table->exist('zq');
//获取理论占用内存尺寸,单位字节
$table->momorySize();

RPC

RPC(Remote Procedure Call):近程过程调用,它是一种通过网络从近程计算机程序上申请服务,而不须要理解底层网络技术的思维。

具体介绍:https://developer.51cto.com/a…

  • 解决分布式系统中,服务之间的调用问题。
  • 近程调用时,要可能像本地调用一样不便,让调用者感知不到近程调用的逻辑。
  • 节点角色阐明:
  • Server: 裸露服务的服务提供方
  • Client: 调用近程服务的服务生产方
  • Registry: 服务注册与发现的注册核心

think-swoole实现RPC性能

服务器端

接口定义app/rpc/interfaces/UserInterface.php

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

实现接口app/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. "查问数据遍历";
    }
}

注册rpc服务config/swoole.php

    'rpc'        => [
        'server' => [
            //开启rpc服务
            'enable'   => true,
            //rpc端口
            'port'     => 9000,
            'services' => [
                //注册服务
                \app\rpc\services\UserService::class
            ],
        ],
        // 如果填写也是能够调用其余服务端
        'client' => [
        ],
    ],

启动服务端

php think swoole start /  php think swoole:rpc

客户端

    'rpc'        => [
        'server' => [
        ],
        'client' => [
            'tp6'=>[
                //服务端的ip地址
                'host'=>'127.0.0.1',
                //服务端对应的端口
                'port'=>'9000'
            ]
            // 更多服务端
        ],
    ],

运行php think rpc:interface生成RPC接口文件app\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']];

在控制器调用

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

定时工作

在think-swoole 2.0版本的时候还是反对自定义定时工作配置,具体参考https://github.com/top-think/…

在3.0就不反对了,在这里介绍一个通用的命令行启动定时工作

php think make:command SwooleTimer

加载命令行config/console.php

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

书写命令脚本app/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()
    {
        // 指令配置
        $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>");
        }
    }

    /**
     * 启动定时工作 次要工作打算在这里书写
     */
    protected function start()
    {
        // https://wiki.swoole.com/#/timer
        $timer_id=swoole_timer_tick(2000,function (){
            echo "2s循环执行须要做的事件".time()."\n";
        });
        $this->output->writeln("Swoole Timer_id:{$timer_id} ");
    }

    /**
     * 革除所有的定时工作
     */
    protected  function stop(){
        swoole_timer_clear_all();
        $this->output->writeln("Swoole Timer  clear all ok");
    }
}

杀死所有指定名称过程

ps -ef | grep swoole | grep -v grep | awk '{print $2}' | xargs kill -9

搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:thinkswoole使用

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址