背景介绍,后端使用laravel8框架,需求扫码登录,扫码成功服务端推送消息给js,js主动获取新,跳转成功页面,扫码登录的业务在这里不详细叙述,有空再写。主要是还需要用的swoole/table的功能,内容太多,本次主要介绍laravel集成swoole实现websocket实现的过程,并且支持wss协议
1、安装swoole版本4.8.11,(5.0以上版本编译失败)
wget https://github.com/swoole/swoole-src/archive/refs/tags/v4.8.11.zip
mv v4.8.11.zip swoole-v4.8.11.zip
unzip swoole-v4.8.11.zip
cd swoole-
cd swoole-src-4.8.11/
phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install
vim /usr/local/php/etc/php.ini
#添加 extension=swoole.so
#重启php-fpm
/etc/init.d/php-fpm restart
#查看扩展是否安装好
php -m | grep swoole
2、在laravel的根目录php artisan make:commad websocket
创建websocket命令
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class Websocket extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'websocket';
/**
* The console command description.
*
* @var string
*/
protected $description = 'this is websocket';
/**
* Create a new command instance.
*
* @return void
*/
private $ws;
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
$this->start();
}
public function start() {
//创建WebSocket Server对象,监听0.0.0.0:9501端口,,通过nginx方向代理支持wss
$this->ws = new \Swoole\WebSocket\Server('127.0.0.1', 9501);
//监听WebSocket连接打开事件
$this->ws->on('Open', function ($ws, $request) {
$ws->push($request->fd, "hello, welcome{$request->fd}\n");
});
//监听WebSocket消息事件
$this->ws->on('Message', function ($ws, $frame) {
echo "Message: {$frame->data}\n";
#可以绑定fd和token关系,使用swoole/table
$ws->push($frame->fd, "server: {$frame->data}");
});
$this->ws->on('request', function ($request, $response) {
$msg = $request->post['message'];
// $server->connections 遍历所有websocket连接用户的fd,给所有用户推送
// 可以通过swoole/table绑定fd->token关系反向找到fd,从而推送给指定用户
foreach ($this->ws->connections as $fd) {
// 需要先判断是否是正确的websocket连接,否则有可能会push失败
//广播推送
if ($this->ws->isEstablished($fd)) {
$this->ws->push($fd, $msg);
$this->info("client is PushMessage\n".$msg);
}
}
});
//监听WebSocket连接关闭事件
$this->ws->on('Close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$this->ws->start();
}
}
3、启动websocket服务端 php artisan websokct
生产环境使用supervisord配置如下
vim /etc/supervisord.conf
[program:websocket]
command=/bin/php artisan websocket
numprocs=1
directory=/home/wwwroot/xxx.xxx.com
user=www
autostart=true
autorestart=true
redirect_stderr=true
stdout_logfile=/var/log/supervisor/websocket.log
#更新配置命令
supervisorctl update
4、nginx反向代理websocket,支持wss协议
server
{
listen 443 ssl http2;
#listen [::]:443 ssl http2;
server_name xxx.xxx.com ;
index index.html index.htm index.php default.html default.htm default.php;
ssl_certificate /usr/local/nginx/conf/ssl/xxx.xxx.com/fullchain.cer;
ssl_certificate_key /usr/local/nginx/conf/ssl/xxx.xxx.com/xxx.xxxcom.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "TLS13-AES-256-GCM-SHA384:TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-128-GCM-SHA256:TLS13-AES-128-CCM-8-SHA256:TLS13-AES-128-CCM-SHA256:EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
ssl_session_cache builtin:1000 shared:SSL:10m;
ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;
#nginx转发websocket服务端处理
location /websocket {
#websocket服务端监听的地址和端口
proxy_pass http://127.0.0.1:9501;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_http_version 1.1;
proxy_set_header Connection "upgrade";
proxy_set_header Upgrade $http_upgrade;
}
5、js端代码
url = `wss://xxx.xxx.com/websocket`;
// 打开一个websocket
let websocket = new WebSocket(url);
// 建立连接
websocket.onopen = () => {
// 发送数据
websocket.send("发送数据");
console.log("websocket发送数据中");
};
// 客户端接收服务端返回的数据
websocket.onmessage = evt => {
console.log("websocket返回的数据:", evt);
};
// 发生错误时
websocket.onerror = evt => {
console.log("websocket错误:", evt);
};
// 关闭连接
websocket.onclose = evt => {
console.log("websocket关闭:", evt);
};
6、curl发送post发送给websocket服务端onRequest(处理消息),websocket服务端收到消息,通过websocket再推送给客户端
public function curl($data)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "http://127.0.0.1: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);
}
$data['message'] = '主动推送消息'.date("Y-m-d H:i:s");
curl($data);
7、js收到消息如下图
![](https://img.haomeiwen.com/i4455227/144e51fb84d09db6.png)
网友评论