使用artisan命令创建Swoole任务
php artisan make:command Swoole
在App\Console\Commands下生成Swoole.php文件
<?php
namespace App\Console\Commands;
use Exception;
use Swoole\Process;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class RealTimePush extends Command
{
private $swoole;
private $pid_file;
protected $signature = 'realtimePush {action}';
protected $description = '实时推送';
public function __construct()
{
$this->pid_file = __DIR__ . '/../../../storage/logs/swoole_websocket_realtime.pid';
}
public function handle()
{
$action = $this->argument('action');
switch ($action) {
case 'stop': //停止命令
$this->stop();
break;
case 'start': //启动命令
$this->start();
break;
default:
$this->error('没有' . $action . '这个命令');
break;
}
}
// 启动服务
public function start()
{
$pid = $this->getPid();
//检测服务是否启动
if ($pid && Process::kill($pid, 0)) {
$this->error('服务已启动');
exit;
}
//创建websocket服务,监听ip:端口
$this->swoole = new \swoole_websocket_server(192.168.0.1, 9500);
$this->swoole->set([
//60秒检测一次,一个连接如果300秒内未向服务器发送任何数据,此连接将被强制关闭
'heartbeat_check_interval' => 60, 'heartbeat_idle_time' => 300,
//进程id存储路径
'pid_file' => $this->pid_file,
]);
//监听WebSocket连接打开事件
$this->swoole->on('open', [$this, 'open']);
//监听WebSocket消息事件
$this->swoole->on('message', [$this, 'message']);
//监听WebSocket主动推送消息事件
$this->swoole->on('request', [$this, 'request']);
//监听WebSocket连接关闭事件
$this->swoole->on('close', [$this, 'close']);
//启动事件
$this->swoole->start();
}
// 建立连接
public function open($swoole, $request)
{
//$request->fd是连接当前页面的ID
if (isset($request->get) && isset($request->get['token'])) {
$swoole->push($request->fd, json_encode(['code' => 200, 'msg' =>'连接成功']));
} else {
$swoole->push($request->fd, json_encode(['code' => 400, 'msg' =>'没有登录']));
//断开连接
$swoole->close($request->fd);
}
}
//接收前端发送的消息
public function message($swoole, $frame)
{
$swoole->push($frame->fd, '已收到发送的消息');
}
// 接收服务器请求
public function request($request, $response)
{
try {
//请求的数据
$post = $request->post;
//拼接redis的key
$key = 'realTimePush' . date('Ymd');
$redis = new \Redis();
$redis->connect('127.0.0.1', 6379);
$redis->auth('passworld');
$redis->select(0);
$datas = [];
//获取所有连接fd
$clients = $this->swoole->getClientList();
//获取队列的长度
$num = $redis->lLen($key);
//连接fd是空 队列里没有推送内容
if (!empty($clients) && $num > 0) {
//循环取出数据
while ($num > 0) {
$data = $redis->rpop($key);
if (!empty($data)) {
$datas[] = json_decode($data, true);
}
$num--;
}
//推送的数据
$result = json_encode(['code' => 200, 'msg' => '成功', 'data' => $datas]);
//循环推送数据到前端
foreach ($clients as $fd) {
if ($this->swoole->isEstablished($fd)) {
if ($this->swoole->push($fd, $result)) {
//Log::info('推送成功');
}
}
}
}
$redis->close();
return true;
} catch (Exception $e) {
Log::error('推送:' . $e->getMessage());
return false;
}
}
// 关闭连接
public function close($swoole, $fd)
{
$swoole->close($fd);
}
// 服务停止
public function stop()
{
if (!$pid = $this->getPid()) {
$this->error('没有服务id');
exit;
}
//关闭服务
if (Process::kill($pid)) {
$this->info('服务已停止');
exit;
}
$this->info('停止服务失败');
}
// 获取进程pid
private function getPid()
{
return file_exists($this->pid_file) ? file_get_contents($this->pid_file) : false;
}
}
启动/关闭Swoole服务命令
//启动服务命令
php artisan realtimePush start
//关闭服务命令
php artisan realtimePush stop
后端手动触发推送
php artisan realtimePush start
var ws = new WebSocket('192.168.0.1:9500');
ws.onopen = function(){
console.log(“open”);
ws.send(“hello”);
};
ws.onmessage = function(evt){
console.log(evt.data)
};
ws.onclose = function(evt){
console.log(“WebSocketClosed!”);
};
ws.onerror = function(evt){
console.log(“WebSocketError!”);
};
$data = [
'code' => 200,
'msg' => '成功',
'data' => '推送内容'
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, '192.168.0.1:9500');
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
$content = curl_exec($curl);
curl_close($curl);
dump($content);