laravel下安装laravels以及websocket的使用
🚀 LaravelS 是 Swoole 和 Laravel/Lumen 之间开箱即用的适配器。
环境要求
安装
1.通过Composer安装(packagist)。有可能找不到3.0
版本,解决方案移步#81。
composer require "hhxsv5/laravel-s:~3.7.0" -vvv
# 确保你的composer.lock文件是在版本控制中
2.注册Service Provider(以下两步二选一)。
Laravel
: 修改文件config/app.php
,Laravel 5.5+支持包自动发现,你应该跳过这步
'providers' => [ //... Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class, ],
Lumen
: 修改文件bootstrap/app.php
$app->register(Hhxsv5\LaravelS\Illuminate\LaravelSServiceProvider::class);
3.发布配置和二进制文件。
每次升级LaravelS后,需重新publish;点击Release去了解各个版本的变更记录。
php artisan laravels publish # 配置文件:config/laravels.php # 二进制文件:bin/laravels bin/fswatch bin/inotify
4.修改配置config/laravels.php
:监听的IP、端口等,请参考配置项。
运行
在运行之前,请先仔细阅读:
注意事项(这非常重要)。
- 操作命令:
php bin/laravels {start|stop|restart|reload|info|help}
。
命令 | 说明 |
---|---|
start | 启动LaravelS,展示已启动的进程列表 “ps -ef|grep laravels“ |
stop | 停止LaravelS,并触发自定义进程的onStop 方法 |
restart | 重启LaravelS:先平滑Stop ,然后再Start ;在Start 完成之前,服务是不可用的 |
reload | 平滑重启所有Task/Worker/Timer进程(这些进程内包含了你的业务代码),并触发自定义进程的onReload 方法,不会重启Master/Manger进程;修改config/laravels.php 后,你只有 调用restart 来完成重启 |
info | 显示组件的版本信息 |
help | 显示帮助信息 |
- 启动选项,针对
start
和restart
命令。
选项 | 说明 |
---|---|
-d|—daemonize | 以守护进程的方式运行,此选项将覆盖laravels.php 中swoole.daemonize 设置 |
-e|—env | 指定运行的环境,如--env=testing 将会优先使用配置文件.env.testing ,这个特性要求Laravel 5.2+ |
-i|—ignore | 忽略检查Master进程的PID文件 |
-x|—x-version | 记录当前工程的版本号(分支),保存在$_ENV /$_SERVER 中,访问方式:$_ENV['X_VERSION'] $_SERVER['X_VERSION'] $request->server->get('X_VERSION') |
运行时
文件:start
时会自动执行php artisan laravels config
并生成这些文件,开发者一般不需要关注它们,建议将它们加到.gitignore
中。
文件 | 说明 |
---|---|
storage/laravels.conf | LaravelS的运行时 配置文件 |
storage/laravels.pid | Master进程的PID文件 |
storage/laravels-timer-process.pid | 定时器Timer进程的PID文件 |
storage/laravels-custom-processes.pid | 所有自定义进程的PID文件 |
与Nginx配合使用(推荐)
gzip on;
gzip_min_length 1024;
gzip_comp_level 2;
gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml application/x-httpd-php image/jpeg image/gif image/png font/ttf font/otf image/svg+xml;
gzip_vary on;
gzip_disable "msie6";
upstream swoole {
# 通过 IP:Port 连接
server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
# 通过 UnixSocket Stream 连接,小诀窍:将socket文件放在/dev/shm目录下,可获得更好的性能
#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 80;
# 别忘了绑Host
server_name laravels.com;
root /yourpath/laravel-s-test/public;
access_log /yourpath/log/nginx/$server_name.access.log main;
autoindex off;
index index.html index.htm;
# Nginx处理静态资源(建议开启gzip),LaravelS处理动态资源。
location / {
try_files $uri @laravels;
}
# 当请求PHP文件时直接响应404,防止暴露public/*.php
#location ~* \.php$ {
# return 404;
#}
location @laravels {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout 120s;
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;
# “swoole”是指upstream
proxy_pass http://swoole;
}
}
启用WebSocket服务器
WebSocket服务器监听的IP和端口与Http服务器相同。
1.创建WebSocket Handler类,并实现接口WebSocketHandlerInterface
。start时会自动实例化,不需要手动创建实例。
fd, request()->all(), session()->getId(), session('xxx'), session(['yyy' => time()])]);
Log::info('WebSocket 连接建立');
$server->push($request->fd, 'Welcome to LaravelS');
// throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
}
public function onMessage(Server $server, Frame $frame)
{
// \Log::info('Received message', [$fram // \Log::info('Received message', [$frame->fd, $frame->data, $frame->opcode, $frame->finish]);
//
// $server->push($frame->fd, $frame->data);e->fd, $frame->data, $frame->opcode, $frame->finish]);
$server->push($frame->fd, $frame->data);
// $arr = [
// 'time' => date('Y-m-d H:i:s')
// ];
// $server->push($frame->fd, json_encode($arr));
// throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
}
public function onClose(Server $server, $fd, $reactorId)
{
Log::info('WebSocket 连接关闭');
// throw new \Exception('an exception');// 此时抛出的异常上层会忽略,并记录到Swoole日志,需要开发者try/catch捕获处理
}
}
2.更改配置config/laravels.php
。
// ...
'websocket' => [
'enable' => true, // 看清楚,这里是true
'handler' => \App\Services\WebSocketService::class,
],
'swoole' => [
//...
// dispatch_mode只能设置为2、4、5,https://wiki.swoole.com/#/server/setting?id=dispatch_mode
'dispatch_mode' => 2,
//...
],
// ...
3.使用SwooleTable
绑定FD与UserId,可选的,Swoole Table示例。也可以用其他全局存储服务,例如Redis/Memcached/MySQL,但需要注意多个Swoole Server
实例时FD可能冲突。
4.与Nginx配合使用(推荐)
参考 WebSocket代理
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
upstream swoole {
# 通过 IP:Port 连接
server 127.0.0.1:5200 weight=5 max_fails=3 fail_timeout=30s;
# 通过 UnixSocket Stream 连接,小诀窍:将socket文件放在/dev/shm目录下,可获得更好的性能
#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 80;
# 别忘了绑Host
server_name laravels.com;
root /yourpath/laravel-s-test/public;
access_log /yourpath/log/nginx/$server_name.access.log main;
autoindex off;
index index.html index.htm;
# Nginx处理静态资源(建议开启gzip),LaravelS处理动态资源。
location / {
try_files $uri @laravels;
}
# 当请求PHP文件时直接响应404,防止暴露public/*.php
#location ~* \.php$ {
# return 404;
#}
# Http和WebSocket共存,Nginx通过location区分
# !!! WebSocket连接时路径为/ws
# Javascript: var ws = new WebSocket("ws://laravels.com/ws");
location =/ws {
# proxy_connect_timeout 60s;
# proxy_send_timeout 60s;
# proxy_read_timeout:如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接;同时,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://swoole;
}
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://swoole;
}
}
5.心跳配置
Swoole的心跳配置
// config/laravels.php 'swoole' => [ //... // 表示每60秒遍历一次,一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭 'heartbeat_idle_time' => 600, 'heartbeat_check_interval' => 60, //... ],
Nginx读取代理服务器超时的配置
# 如果60秒内被代理的服务器没有响应数据给Nginx,那么Nginx会关闭当前连接 proxy_read_timeout 60s;
HTML实战代码
<script type="text/javascript">
if(window.WebSocket){
// 端口和ip地址对应不要写错
var webSocket = new WebSocket("ws://127.0.0.1:5200");
webSocket.onopen = function (event) {
console.log('webSocket 连接成功');
};
// 连接关闭时触发
webSocket.onclose = function (event) {
console.log("WebSocket 关闭连接");
}
//收到服务端消息回调
webSocket.onmessage = function (event) {
var content = document.getElementById('content');
content.innerHTML = content.innerHTML.concat('<p style="margin-left:20px;height:20px;line-height:20px;">'+event.data+'</p>');
console.log(event.data)
}
var sendMessage = function(){
var data = document.getElementById('message').value;
webSocket.send(data);
}
}else{
console.log("您的浏览器不支持WebSocket");
}
</script>
实战截图
结束语
希望本文可以帮助大家学习如何使用websocket。👍