1、创建WsSwoole.php文件(大驼峰命名,自命名)
在项目根目录执行以下命令
#在app/Console/Commands增加一个Swoole.php的文件
php artisan make:command WsSwoole
2、在Kernel.php里增加命令列表(如果定时任务必须加,这个可加可不加,建议加)
Commands\Swoole::Class
<?php
namespace App\Console;
use App\Console\Commands\AccessTokenRevoke;
use App\Console\Commands\UploadPart;
use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
class Kernel extends ConsoleKernel
{
/**
* The Artisan commands provided by your application.
*
* @var array
*/
protected $commands = [
WsSwoole::Class,//这个可以不加
UploadPart::class
];
/**
* Define the application's command schedule.
*
* @param \Illuminate\Console\Scheduling\Schedule $schedule
* @return void
*/
protected function schedule(Schedule $schedule)
{
$schedule->command('accessToken:revoke')->everyFiveMinutes(); //每五分钟调度一次token废弃任务
$schedule->command('pst:uploadpart')->dailyAt('3:00'); //每天3点删除上传产生的碎片
}
/**
* Register the commands for the application.
*
* @return void
*/
protected function commands()
{
$this->load(__DIR__.'/Commands');
require base_path('routes/console.php');
}
}
3、编辑WsSwoole文件
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class WsSwoole extends Command
{
public $ws;
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'swoole {action?}';
/**
* The console command description.
*
* @var string
*/
protected $description = 'swoole';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
$action = $this->argument('action');
switch ($action) {
case 'restart':
$this->info('swoole server restarted');
break;
case 'close':
$this->info('swoole server stoped');
break;
default:
$this->start();
break;
}
}
public function start()
{
//创建websocket服务器对象,监听0.0.0.0:9501端口
$this->ws = new \swoole_websocket_server("0.0.0.0", 9501);
//上面端口可以写到配置文件中 配置文件大概样式在最后
//$this->ws =new \swoole_websocket_server(config('web_socket.host'),config('web_socket.port'), SWOOLE_PROCESS, SWOOLE_SOCK_TCP );
//开启ssl模式
// $this->ws = new \swoole_websocket_server("0.0.0.0", 9501,SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
//配置ssl模式
// $this->ws->set([
// 'ssl_key_file' => '/var/www/html/ssl/4033464_cxh520.top.key',
// 'ssl_cert_file' => '/var/www/html/ssl/4033464_cxh520.top.pem'
// ]);
//监听WebSocket连接打开事件
$this->ws->on('open',[$this,'open']);
//监听WebSocket消息事件
$this->ws->on('message',[$this,'message']);
//监听WebSocket主动推送消息事件
$this->ws->on('request',[$this,'request']);
//监听WebSocket连接关闭事件
$this->ws->on('close',[$this,'close']);
$this->ws->start();
}
/**
* 建立连接
* @param $ws
* @param $request
*/
public function open($ws, $request){
var_dump($request->fd . "连接成功");
}
/**
* 接收消息
* @param $ws
* @param $frame
*/
public function message($ws,$frame){
var_dump('发送成功');
}
/**
* 接收请求
* @param $request
* @param $response
*/
public function request($request,$response){
}
/**
* 关闭连接
* @param $ws
* @param $fd
*/
public function close($ws,$fd){
}
}
优化
$tool=WebSocketTool::getWebSocketTool();//添加回调类 把open,message,request,close等放进WebSocketTool中,这样封装看起来比较整洁
$this->ws->on('open',array($tool,'onOpen'));
$this->ws->on('message',array($tool,'onMessage'));
$this->ws->on('close',array($tool,'onClose'));
$this->serv->start();
WebSocketTool部分代码大概这样
<?php
namespace App\Tools;
use App\Models\Pst;
use App\Models\Role;
use App\Models\User;
use App\WebSocket\WebSocketClient;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Redis;
/**
* 短信工具类
*/
class WebSocketTool
{
static private $webSocketTool;
private $table;
private $config;
private $userTool;//用户工具类
private $notifyTool;//通知工具类
private $redis_u_info;//redis中存放user信息的hash表明
private $redis_uid_fd;//user_id 关联fd hash表名
/**
*私有构造函数防止new
*/
private function __construct()
{
$this->config = config('web_socket');
$this->userTool = UserTool::getUserTool();
$this->notifyTool = NotifyTool::getNotifyTool();
$this->redis_u_info = $this->config['redis']['u_info'];
$this->redis_uid_fd = $this->config['redis']['uid_fd'];
}
/**
* 单例模式
*/
static public function getWebSocketTool()
{
if (self::$webSocketTool instanceof self) {
return self::$webSocketTool;
} else {
return self::$webSocketTool = new self;
}
}
/**
* 防止被克隆
*/
private function _clone()
{
}
/**
* 监听用户连接事件
* @param \swoole_websocket_server $server
* @param \swoole_http_request $request
*/
public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request)
{
if (!array_key_exists('client_type', $request->header)) {//判断是否从业务逻辑推送
$user = User::find(FunctionTool::decrypt_id(($request->get)['user_id']));
$r_data = [];//需要压入or取出的redis的数据
//放入redis缓存中
$fd = $request->fd;
$r_data = [
'fd' => $fd,
'user_id' => $user->id,
'name' => $user->name,
];
WsSendMessageTool::bindFdUser($this->redis_u_info, $this->redis_uid_fd, $r_data, $fd, $user->id);//绑定用户信息
dump('ws服务器用户绑定');
dump(Redis::hgetall($this->redis_u_info), Redis::hgetall($this->redis_uid_fd));
}
}
/**
* 监听用户连接关闭状态
* @param \swoole_websocket_server $server
* @param int $fd
*/
public function onClose(\swoole_websocket_server $server, int $fd)
{
dump('连接断开逻辑');
WsSendMessageTool::removeFdUser($this->redis_u_info, $this->redis_uid_fd, $fd);
}
/**
* 监听客户端向服务端推送数据
* @param \swoole_websocket_server $server
* @param \swoole_websocket_frame $frame
*/
public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame)
{
}
}
4、前端代码
const ws = new WebSocket('ws://服务器ip:9501');
ws.onopen = () =>{
console.log("连接成功");
ws.send('111');
}
ws.onmessage = ({data}) =>{
}
ws.onclose = () =>{
}
5、主动推送代码(放在任何控制器位置调用即可)
public function swooleCurl($data)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://服务器ip:9501");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_exec($curl);
curl_close($curl);
}
6、服务器项目根目录运行swoole,下面两条命令都可以
#启动
php artisan swoole start
#启动并守护
php artisan swoole &
启动命令
与WsSwoole文件相关
protected $signature = ‘swoole {action?}’;
如果改为 protected $signature = ‘swoole:action {action}’;//问号可以不用
则启动命令为 php artisan swoole:action start
封装优化
在WsSwoole中start()的优化配置文件
<?php
return [
/*
* swoole服务器启动的地址&端口
*/
'host' => '0.0.0.0',
'port' => 9501,
/*
*swoole演示聊天室启动的地址&端口
*/
'chat_host'=>'0.0.0.0',
'chat_port'=>9502,
'redis' => [
'u_info'=>'u_info',//存放用户通道绑定信息的hash表名
'uid_fd'=>'uid_fd',//通道id与user_id关联表名
],
];