1 Laravel 生成命令行
php artisan make:command SwooleDemo
<?php namespace App\Console\Commands; use Illuminate\Console\Command; class SwooleDemo extends Command { /** * The name and signature of the console command. * * @var string */ protected $signature = 'swoole:demo'; /** * The console command description. * * @var string */ protected $description = '这是关于swoole的一个测试demo'; private static $server = null; /** * Create a new command instance. * * @return void */ public function __construct() { parent::__construct(); } /** * Execute the console command. * * @return int */ public function handle() { $server = self::getWebSocketServer(); $server->on('open',[$this,'onOpen']); $server->on('message', [$this, 'onMessage']); $server->on('close', [$this, 'onClose']); $server->on('request', [$this, 'onRequest']); $this->line("swoole服务启动成功 ..."); $server->start(); } // 获取服务 public static function getWebSocketServer() { if (!(self::$server instanceof \swoole_websocket_server)) { self::setWebSocketServer(); } return self::$server; } // 服务处始设置 protected static function setWebSocketServer():void { self::$server = new \swoole_websocket_server("0.0.0.0", 9600); self::$server->set([ 'worker_num' => 1, 'heartbeat_check_interval' => 60, // 60秒检测一次 'heartbeat_idle_time' => 121, // 121秒没活动的 ]); } // 打开swoole websocket服务回调代码 public function onOpen($server, $request) { if ($this->checkAccess($server, $request)) { self::$server->push($request->fd,"打开swoole服务成功!"); } } // 给swoole websocket 发送消息回调代码 public function onMessage($server, $frame) { $server->push($frame->fd, '第几个用户给我发送'.$frame->fd); } // websocket 关闭回调代码 public function onClose($serv,$fd) { $this->line("客户端 {$fd} 关闭"); } // 校验客户端连接的合法性,无效的连接不允许连接 public function checkAccess($server, $request):bool { $bRes = true; if (!isset($request->get) || !isset($request->get['token'])) { self::$server->close($request->fd); $this->line("接口验证字段不全"); $bRes = false; } else if ($request->get['token'] !== "123456") { $this->line("接口验证错误"); $bRes = false; } return $bRes; } // 启动websocket服务 public function start() { self::$server->start(); } }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>swoole测试</title> <meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"></head> <body> <h1>这是一个测试</h1> <button onclick="sendMsg()">点击发送</button> </body> <script> var ws; //websocket实例 var lockReconnect = false; //避免重复连接 var wsUrl = 'ws://homestead.work:9600?page=home&token=123456'; function initEventHandle() { ws.onclose = function() { reconnect(wsUrl); }; ws.onerror = function() { reconnect(wsUrl); }; ws.onopen = function() { //心跳检测重置 heartCheck.reset().start(); }; ws.onmessage = function(event) { //如果获取到消息,心跳检测重置 //拿到任何消息都说明当前连接是正常的 var data = JSON.parse(event.data); heartCheck.reset().start(); } } createWebSocket(wsUrl); function sendMsg(){ console.log(1111111); ws.send("send by myself"); } /** * 创建链接 * @param url */ function createWebSocket(url) { try { ws = new WebSocket(url); initEventHandle(); } catch(e) { reconnect(url); } } function reconnect(url) { if (lockReconnect) return; lockReconnect = true; //没连接上会一直重连,设置延迟避免请求过多 setTimeout(function() { createWebSocket(url); lockReconnect = false; },2000); } //心跳检测 var heartCheck = { timeout: 60000, //60秒 timeoutObj: null, serverTimeoutObj: null, reset: function() { clearTimeout(this.timeoutObj); clearTimeout(this.serverTimeoutObj); return this; }, start: function() { var self = this; this.timeoutObj = setTimeout(function() { //这里发送一个心跳,后端收到后,返回一个心跳消息, //onmessage拿到返回的心跳就说明连接正常 ws.send("heartbeat"); self.serverTimeoutObj = setTimeout(function() { //如果超过一定时间还没重置,说明后端主动断开了 ws.close(); //如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次 },self.timeout); },this.timeout); }, header: function(url) { window.location.href = url } } </script> </html>
运行命令开启端口监听 php artisan swoole:demo