持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
php安装swoole扩展请移步swoole官方网站:
我这里使用的yum源安装的php环境,在安装的时候已经集成swoole扩展,具体环境安装步骤请移步《CentOS7.8使用yum安装PHP 7.4》
1:安装laravel-swoole扩展:
composer require swooletw/laravel-swoole
2:生成配置文件, 运行以下命令在 /config 命令看生成配置文件 swoole_http.php 并 swoole_websocket.php
php artisan vendor:publish --tag=laravel-swoole
3: 在 Laravel 应用中使用 Swoole 之前,先通过 Composer 安装 LaravelS 扩展包:
LaravelS 官方文档: github.com/hhxsv5/lara…
composer require hhxsv5/laravel-s
该命令会发布配置文件 laravels.php 到 config 目录下,以及脚本文件到 bin 目录下
php artisan laravels publish
4: 如果想用 websocket ,在 config/laravels.php 下
'websocket' => [
'enable' => true,
'handler' => \App\Services\WebSocketService::class,
],
5:WebSocketService.php
namespace App\Services;
use Hhxsv5\LaravelS\Swoole\WebSocketHandlerInterface;
use Illuminate\Support\Facades\Log;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
class WebSocketService implements WebSocketHandlerInterface
{
public function __construct()
{
}
// 连接建立时触发
public function onOpen(Server $server, Request $request)
{
// 在触发 WebSocket 连接建立事件之前,Laravel 应用初始化的生命周期已经结束,你可以在这里获取 Laravel 请求和会话数据
// 调用 push 方法向客户端推送数据,fd 是客户端连接标识字段
Log::info('WebSocket 连接建立');
$server->push($request->fd, 'Welcome to WebSocket Server built on LaravelS');
}
// 收到消息时触发
public function onMessage(Server $server, Frame $frame)
{
$server->push($frame->fd, 'This is a message sent from WebSocket Server at ' . date('Y-m-d H:i:s'));
}
// 关闭连接时触发
public function onClose(Server $server, $fd, $reactorId)
{
Log::info('WebSocket 连接关闭');
}
}
6:启动laravels
cd bin
php laravels start //使用该命令启动laravels
php laravels stop //使用该命令停止laravels
php laravels reload //使用该命令重载laravels
php laravels restart //使用该命令重启laravels
php laravels info //使用该命令显示laravels信息
php laravels help //使用该命令显示laravels帮助
注意启动成功之后的端口号,这个配置nginx的时候会用到,我这里的端口号是5200。
7:配置.env文件
将一下代码添加至.env文件中。
#这里的 IP 需要和 nginx upstream 中配置的监听 IP 保持一致
LARAVELS_LISTEN_IP=0.0.0.0
LARAVELS_DAEMONIZE=true
8:测试swoole是否可用。
在根目录下创建ws_server.php文件
<?php
//创建WebSocket Server对象,监听0.0.0.0:9502端口
$ws = new Swoole\WebSocket\Server('0.0.0.0', 9502);
//监听WebSocket连接打开事件
$ws->on('open', function ($ws, $request) {
$ws->push($request->fd, "hello, welcome\n");
});
//监听WebSocket消息事件
$ws->on('message', function ($ws, $frame) {
echo "Message: {$frame->data}\n";
$ws->push($frame->fd, "server: {$frame->data}");
});
//监听WebSocket连接关闭事件
$ws->on('close', function ($ws, $fd) {
echo "client-{$fd} is closed\n";
});
$ws->start();
然后在服务器使用命令行执行
php ws_server.php
前端代码:我这里使用的vue3.0语法
import { useRouter } from "vue-router";
import {
PropType,
ref,
watch,
reactive,
toRefs,
inject,
provide,
onMounted
} from "vue";
// 引入公共js文件
import utils from "/@/assets/js/public/function";
// 定义返回的类型
interface dataRef {
close: () => void;
}
export default {
name: "Drawer",
// VUE3语法 setup函数
// setup官方文档:https://www.vue3js.cn/docs/zh/guide/composition-api-setup.html#参数
setup(props: any, content:any): dataRef
{
/**
* @name: 声明data
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const data = reactive({
drawerShow: common.drawerShow,
});
/**
* @name: 关闭组件
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const close = () => {
data.drawerShow = false;
common.drawerShow = data.drawerShow;
}
// 初始化客户端套接字并建立连接
var sock = new WebSocket("ws://111.231.162.140:9502");
// 连接建立时触发
sock.onopen = (event) => {
console.log("Connection open ...");
change();
}
// 接收到服务端推送时执行
sock.onmessage = (event) => {
var msg = event.data;
console.log(event);
console.log("webscoket 接收到返回消息!");
};
// 连接关闭时触发
sock.onclose = (event) => {
console.log("Connection closed ...");
}
// 发送消息给webscoket
const change = () => {
var msg = "你好啊~";
// 将输入框变更信息通过 send 方法发送到服务器
if (sock.readyState === 1)
{
sock.send(msg);
console.log('消息发送---success!');
}
else
{
console.log('消息发送---faild!');
}
};
/**
* @name: 将data绑定值dataRef
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const dataRef = toRefs(data);
return {
close,
...dataRef
}
},
}
这里大概做一下解释,setup中的代码在页面加载完成的时候会执行,和webscoket相关的代码这里基本上都有注释。
我测试得到的结果:
前端:
后端:
这里就是使用原生代码测试一下,我们安装的swoole是否可以访问。
9:配置nginx支持webscoket
# webscoket配置
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream laravels {
# Connect IP:Port # 此处的端口号要与laravel-s启动的端口号相同
server 0.0.0.0:5200 weight=5 max_fails=3 fail_timeout=30s;
keepalive 16;
}
# upstream swoole {
# # Connect IP:Port
# server 0.0.0.0:5200 weight=5 max_fails=3 fail_timeout=30s;
# # Connect UnixSocket Stream file, tips: put the socket file in the /dev/shm directory to get better performance
# #server unix:/yourpath/laravel-s-test/storage/laravels.sock weight=5 max_fails=3 fail_timeout=30s;
# #server 192.168.1.1:5200 weight=3 max_fails=3 fail_timeout=30s;
# #server 192.168.1.2:5200 backup;
# keepalive 16;
# }
server {
listen 443;
server_name xxx.xxx;#填写你的域名
index index.html index.htm index.php;#默认打开页面
root /xx/xx/xxx/xxx/xx/public;#你的index.php路径
# error_page 404 /index.html;
autoindex off;
#https配置
ssl on;
ssl_certificate xxx/xxxx/xxxx_xxxx.xxx.pem;
ssl_certificate_key xxx/xxxx/xxxx_xxxx.xxx;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
#开启gzip功能,加快网站打开速度
gzip on;
#开启gzip静态压缩功能
gzip_static on;
#gzip缓存大小
gzip_buffers 4 16k;
#gzip http版本
gzip_http_version 1.1;
#gzip 压缩级别 1-10
gzip_comp_level 2;
#gzip 压缩类型
gzip_types text/plain application/javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;# 是否在http header中添加Vary: Accept-Encoding,建议开启gzip_vary on;
proxy_read_timeout 60s;
location ~ .php(.*)$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
# location /
# {
# #如果是二级目录就用 rewrite ^/文件夹名称/(.*)$ /index.php?s=/$1 last;)
# if (!-e $request_filename)
# {
# rewrite ^(.*)$ /index.php?s=/$1 last;
# break;
# }
# }
# Nginx 处理静态资源,LaravelS 处理动态资源
location / {
index index.html;
# vue 动态路由原始配置
# try_files $uri $uri/ /index.html;
# laravels 结合vue动态路由配置
try_files $uri $uri @laravels/ /index.html;
}
# Http and WebSocket are concomitant, Nginx identifies them by "location"
# !!! The location of WebSocket is "/ws"
# Javascript: var ws = new WebSocket("ws://todo-s.test/ws");
# 处理 WebSocket 通信
location /websocket {
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
# proxy_read_timeout: Nginx will close the connection if the proxied server does not send data to Nginx in 60 seconds; At the same time, this close behavior is also affected by heartbeat setting of Swoole.
proxy_read_timeout 60s;
proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://127.0.0.1:5200; #此处的端口号要与laravel-s启动的端口号相同
}
# laravels 配置
location @laravels {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout 60s;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Real-PORT $remote_port;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Scheme $scheme;
proxy_set_header Server-Protocol $server_protocol;
proxy_set_header Server-Name $server_name;
proxy_set_header Server-Addr $server_addr;
proxy_set_header Server-Port $server_port;
proxy_pass http://127.0.0.1:5200; #此处的端口号要与laravel-s启动的端口号相同
}
}
将上边我使用xxx代替的部分改成你自己的信息。
特别说明一下:我这里使用了ssl证书,如果您没有相关的配置,把https那部分换掉就好。
具体的配置含义,请参考官方文档:
10:测试laravel-swoole
Laravel-swoole的优势就是将swoole插件集成至laravel-s插件中,当前laravel-s插件启动的时候,同时持久化的启动了swoole,不需要我们再服务器端再启动一次swoole。
经过我们上边的配置,基本上就已经启动了swoole,经过我们的测试,原生情况下,我们的swoole是没有问题的,如果在框架中测试出问题,那么只能是我们框架这边配置的问题,关于这方面laravel-swoole为我们提供了日志:
storage/logs目录下
我测试使用的前端代码:
import { useRouter } from "vue-router";
import {
PropType,
ref,
watch,
reactive,
toRefs,
inject,
provide,
onMounted
} from "vue";
// 引入公共js文件
import utils from "/@/assets/js/public/function";
// 定义返回的类型
interface dataRef {
close: () => void;
}
export default {
name: "Drawer",
// VUE3语法 setup函数
// setup官方文档:https://www.vue3js.cn/docs/zh/guide/composition-api-setup.html#参数
setup(props: any, content:any): dataRef
{
/**
* @name: 声明data
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const data = reactive({
drawerShow: common.drawerShow,
});
/**
* @name: 关闭组件
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const close = () => {
data.drawerShow = false;
common.drawerShow = data.drawerShow;
}
// 初始化客户端套接字并建立连接
var sock = new WebSocket("wss://guanchao.site/websocket/");
// 连接建立时触发
sock.onopen = (event) => {
console.log("Connection open ...");
change();
}
// 接收到服务端推送时执行
sock.onmessage = (event) => {
var msg = event.data;
console.log(event);
console.log("webscoket 接收到返回消息!");
};
// 连接关闭时触发
sock.onclose = (event) => {
console.log("Connection closed ...");
}
// 发送消息给webscoket
const change = () => {
var msg = "你好啊~";
// 将输入框变更信息通过 send 方法发送到服务器
if (sock.readyState === 1)
{
sock.send(msg);
console.log('消息发送---success!');
}
else
{
console.log('消息发送---faild!');
}
};
/**
* @name: 将data绑定值dataRef
* @author: camellia
* @email: guanchao_gc@qq.com
* @date: 2021-01-10
*/
const dataRef = toRefs(data);
return {
close,
...dataRef
}
},
}
前端console显示:
我这里基本上就算是链接成功了。
更详细的配置:请参考laravel-s官方文档:
有好的建议,请在下方输入你的评论。
欢迎访问个人博客 guanchao.site
欢迎访问我的小程序:打开微信->发现->小程序->搜索“时间里的”