用thinkphp6框架的think-swoole实现websocket的onRequest
回调事件
为什么要写这个onRequest回调
1.用户链接socket后发送消息触发对应消息相应并回复 satisfy
2.用户链接socket后 我们在后台主动触发按钮调用接口去主动发送给指定用户 no satisfy
so,我们修改以下代码.
1.修改thinkphp6的底层类vendor/topthink/think-swoole/src/concerns/InteractsWithHttp.php
第96行
/**
* "onRequest" listener.
*
* @param Request $req
* @param Response $res
*/
public function onRequest($req, $res)
{
/**
* TinyMeng update start
*/
$httpRequest = config("swoole.websocket.httpRequest");
if(!empty($httpRequest)){
if(isset($req->get['websocket'])){
$websocket = new $httpRequest($this->getServer());
return $websocket->onRequest($req,$res);
}else{
//return true;
}
}
/** Tinymeng end */
$args = func_get_args();
$this->runInSandbox(function (Http $http, Event $event, App $app, Middleware $middleware) use ($args, $req, $res) {
$event->trigger('swoole.request', $args);
//兼容var-dumper
if (class_exists(VarDumper::class)) {
$middleware->add(ResetVarDumper::class);
}
$request = $this->prepareRequest($req);
try {
$response = $this->handleRequest($http, $request);
} catch (Throwable $e) {
$response = $this->app
->make(Handle::class)
->render($request, $e);
}
$this->sendResponse($res, $response, $app->cookie);
});
}
2.修改配置文件 config\swoole.php
<?php
use app\common\service\swoole\WebsocketMessage;
use app\common\service\swoole\SocketHandler;
use think\swoole\websocket\socketio\Parser;
return [
'server' => [
'host' => env('SWOOLE_HOST', '127.0.0.1'), // 监听地址127.0.0.1
'port' => env('SWOOLE_PORT', 9502), // 监听端口
'mode' => SWOOLE_PROCESS, // 运行模式 默认为SWOOLE_PROCESS
'sock_type' => SWOOLE_SOCK_TCP, // sock type 默认为SWOOLE_SOCK_TCP
'options' => [
'pid_file' => runtime_path() . 'swoole.pid',
'log_file' => runtime_path() . 'swoole.log',
'daemonize' => true,//守护进程方式运行
// Normally this value should be 1~4 times larger according to your cpu cores.
'reactor_num' => swoole_cpu_num(),
'worker_num' => swoole_cpu_num(),
'task_worker_num' => swoole_cpu_num(),
'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,
],
],
'websocket' => [
'enable' => true,
'handler' => SocketHandler::class,//SocketHandler
'httpRequest' => WebsocketMessage::class,//监听onRequest回调
'parser' => Parser::class,
'ping_interval' => 25000,
'ping_timeout' => 60000,
'room' => [],
'listen' => [],
'subscribe' => [],
],
//热更新
'hot_update' => [
'enable' => env('APP_DEBUG', false),
'name' => ['*.php'],
'include' => [app_path(),config_path()],
'exclude' => [],
],
];
3.监听用户SocketHandler触发 app\common\service\swoole\SocketHandler
<?php
namespace app\common\service\swoole;
use Swoole\Server;
use think\Config;
use think\Request;
use Swoole\Websocket\Frame;
use app\common\service\CommonService;
use think\swoole\contract\websocket\HandlerInterface;
class SocketHandler implements HandlerInterface
{
/** @var Websocket */
protected $websocket;
/** @var Config */
protected $config;
/**
* SocketHandler constructor.
* @Author: TinyMeng <666@majiameng.com>
* @param \Swoole\Server $server
* @param Config $config
*/
public function __construct(Server $server, Config $config)
{
$this->config = $config;
}
/**
* 监听用户连接事件
* @Author: TinyMeng <666@majiameng.com>
* @param int $fd
* @param Request $request
*/
public function onOpen($fd, Request $request){
CommonService::writeLog("fd:".$fd."连接");
}
/**
* 监听用户断开事件
* @Author: TinyMeng <666@majiameng.com>
* @param int $fd
* @param int $reactorId
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function onClose($fd, $reactorId){
CommonService::writeLog("fd:".$fd."断开");
return true;
}
/**
* 监听用户message事件
* @Author: TinyMeng <666@majiameng.com>
* @param Frame $frame
* @return bool
*/
public function onMessage(Frame $frame){
$packet = trim($frame->data);
CommonService::writeLog("onMessage:".$packet.".");
return true;
}
}
4.监听onRequest回调,程序主动触发给用户 app\common\service\swoole\WebsocketMessage
<?php
namespace app\common\service\swoole;
use Swoole\Websocket\Frame;
use Swoole\WebSocket\Server;
class WebsocketMessage extends Websocket
{
/**
* \Swoole\Server
* @Author: TinyMeng <666@majiameng.com>
* Websocket constructor.
* @param Server $server
*/
public function __construct(Server $server)
{
parent::__construct($server);
}
/**
* onRequest回调
* //127.0.0.1:9502/?websocket=1&action=ONLINEADD&packet=
* @Author: TinyMeng <666@majiameng.com>
* @param $req
* @param $respone
*/
public function onRequest($req, $respone){
if (!empty($req->get['packet'])) {
CommonService::writeLog("onRequest:".$req->get['packet'].".");
}
$respone->end("success");
}
}
5.主动触发发送
use tinymeng\tools\HttpRequest;
try{
$url = "//127.0.0.1:9502/";
$packet_array = [
'websocket'=>1,
'trigger'=>1,
'packet'=>json_encode($data),//发送的消息内容
];
HttpRequest::httpGet($url,$packet_array);
}catch (\Exception $exception){
ExceptionHandle::sendErrorEmail($exception);
return false;
}
tp6, 多应用情况下, 直接访问http://ip:端口, 好像会路由报错
这里的修改只是为了让服务端可以给客户端发送socket,并不是让swoole接管http来替代php-fpm,当然你可以替代的话效率也是很高的,但是我不知道tp框架会不会有其他问题|´・ω・)ノ
你好, 其实我也不是想用来接管php-fpm, 只是因为多应用主动触发发送,curl http://127.0.0.1:9502会提示控制器不存在:appcontrollerSwoole。
请问下能怎么处理
这个好说,你按照我的配置修改,不要让onRequest 去访问到控制器,也就是你可以创建一个所有项目可以使用的class就可以,比如我创建到了这里 appcommonserviceswooleWebsocketMessage.php
<?php namespace app\common\service\swoole; use app\common\models\ConstCode; use app\common\models\mongodb\OnlineModel; use app\common\models\redisdb\RemindUnreadCountModel; use app\common\models\redisdb\TeamUpdateTimeRedisModel; use app\common\service\paper\CommentSocketService; use app\common\service\paper\XPaperSocketService; use app\common\service\user\TeamService; use Swoole\Websocket\Frame; use Swoole\WebSocket\Server; use app\common\service\CommonService; class WebsocketMessage extends Websocket { /** * \Swoole\Server * @Author: TinyMeng <666@majiameng.com> * Websocket constructor. * @param Server $server */ public function __construct(Server $server) { parent::__construct($server); } /** * onRequest回调 * http://127.0.0.1:9502/?websocket=1&action=ONLINEADD&packet= * @Author: TinyMeng <666@majiameng.com> * @param $req * @param $respone */ public function onRequest($req, $respone){ if (!empty($req->get['packet'])) { /** 通过Mq过来的数据包 */ $packet = $req->get['packet'];//接收到的包数据 $packet_array = json_decode($packet,true); self::writeLog("onRequest+++++++++++++++++".$packet_array['action']); //发送数据到当前群组 $this->sendMessage($packet_array); //trigger 当前项目触发 // if (!empty($req->get['trigger'])) { // self::writeLog("onRequest trigger+++++++++++++++++".$packet_array['action']); // //发送数据的mq // $this->sendMq($packet_array); // } } $respone->end("success"); } }有问题的话可以直接在下面留言
6666666666666666666666666
这次我把代码补全了,很easy
呕吼 能看懂的人很少哦