官网文档
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.html
或 html\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…
生成事件
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…
先定结构在进行操作数据(原生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