给当前在线浏览用户推送优惠券,或者刺激用户消费的话术
今天我们主要是借助Laravel Broadcasting你可以使用上时下很热的Websocket技术
1 . 基于laravel的事件广播系统
2 . 基于workman通过长连接
3 . 基于swoole长连接
相同点:三者都可以推送广播事件
区别:1. 事件广播系统更适合局部小范围的laravel项目使用(适合单一用途laravel项目)支持单进程、多线程
workerman则是使用纯php实现的socket框架(适合中小型长连接项目)支持多进程、多线程
swoole是使用C语言实现的socket通信框架(适合大中型长连接项目)支持多进程、多线程
具体流程如下图:
图中术语解释:
laravel-echo-server:使用 socket.io 机制实现的 broadcasting 服务端
laravel-echo:laravel-echo是 laravel broadcasting 的客户端。注意,laravel-echo 并不是 laravel-echo-server 专属的客户端, laravel-echo 有两种连接机制可以选:pusher 和 socket.io 。 而 laravel-echo-server 是开发出来专门用于 socket.io连接的服务端。如果你使用的是 pusher,那么不需要使用 laravel-echo-server ,但是你依然要使用 laravel-echo
Socket.IO:websocket 的一种nodejs实现。laravel-echo 如果要使用socket.io 则需要先安装 socket.io-client。
Predis:redis客户端的php实现,如果要使用redis作为广播机制的实现,则需要先安装 predis
Laravel Event:广播事件类
Laravel Queue:广播机制是基于queue机制来实现的
Redis Sub/Pub:Redis的订阅机制。laravel-echo-server本质上只是一个Redis订阅服务的订阅者。
根据这幅图我们可以知道事件的广播机制流程:
Laravel 5.4.36 (广播机制在 5.4 以后进行了一次重构,并正式加入文档,所以请务必使用 5.4 及其以上版本)
PHP 7.1.13
Redis 3.2.1
1 .
项目构建
composer create-project laravel/laravel laravel --prefer-dist 5.4.*
2 .
让Laravel将Event发布到Redis
2.1 打开 config/app.php 找到 ‘provides’ 属性,将 BroadcastServiceProvider 前的注释去掉
App\Providers\AppServiceProvider::class,
App\Providers\AuthServiceProvider::class,
App\Providers\BroadcastServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
2.2 设置广播路由
打开广播路由配置文件 routes/channels.php ,增加一个新的广播通道 news
id === (int) $id;
});
Broadcast::channel('news', function ($user, $id) {
return true;
});
该channel永远返回true意味着无论收听者是谁,他都会收听到最新的广播。
2.3 设置Redis连接
由于广播机制是基于queue机制实现的。所以queue的存储设置会直接决定广播事件的存储位置。编辑 .env 文件,修改 QUEUE_DRIVER=redis
BROADCAST_DRIVER=redis
CACHE_DRIVER=file
SESSION_DRIVER=file
SESSION_LIFETIME=120
QUEUE_DRIVER=redis
项目添加 predis依赖,在项目根目录下执行:
composer require predis/predis
2.4 建立Event
项目根目录执行以下命令,自动生成News Event对象:
php artisan make:event News
app 目录下多出来一个 Events目录,在该目录下产生了广播事件类 News.php
修改app/Events/News.php
文件
增加对 ShouldBroadcast 的实现
修改broadcastOn 方法,使用公共广播通道 news
修改构造函数
新增broadcastWith 方法 向客户端推送消息
message = $news_message;
}
/**
* 获取事件广播的频道.
*
* @return \Illuminate\Broadcasting\Channel|array
*/
public function broadcastOn()
{
return new Channel('news');
// return new PrivateChannel('channel-name');
}
/**
* 获取广播数据
*
* @return array
*/
public function broadcastWith(){
return ['message'=>$this->message];
}
}
2.5 新增php artisan命令触发广播事件
Artisan::command('bignews', function () {
broadcast(new \App\Events\News(date('Y-m-d h:i:s A').": BIG NEWS!"));
$this->comment("news sent");
})->describe('Send news');
执行 bignews 命令:
$ php artisan bignews
news sent
通过 redis-cli 查看当前redis中的数据:
127.0.0.1:6379> keys *
1) "queues:default"
Laravel的广播机制成功的连接上了 Redis!
3 .
让Laravel Queue Worker消费Event
如果项目之前没有使用过队列,请去官方文档看一下队列配置
Laravel 的队列系统
新开一个终端窗口,并在项目根目录下启动 Laravel Queue Worker
$ php artisan queue:work
回到之前的终端窗口,再广播一个news Event:
php artisan bignews
queue worker的终端界面看到该Event已经被检测到,并通过Redis Sub/Pub机制传播出去了
$ php artisan queue:work
[2019-04-26 01:47:22] Processing: App\Events\News
[2019-04-26 01:47:22] Processed: App\Events\News
还记得之前通过Laravel广播事件之后redis中会产生一个 queue:default对象么?这次如果你快速的通过 keys * 命令查询redis中的对象,你会发现 queue:default 每次被产生出来就会迅速的被 queue worker消费掉
127.0.0.1:6379> keys *
1) "queues:default"
127.0.0.1:6379> keys *
(empty list or set)
Laravel Queue Worker连接成功!
接下来我们来让 laravel-echo-server 订阅Redis Sub
4 .
让 laravel-echo-server 订阅Redis Sub
4.1 安装
如果使用pusher可以直接laravel就可以了
如果使用 Redis + socket.io 则需要使用开源项目 laravel-echo-server 。所以我们现在要使用 laravel-echo-server。
全局安装laravel-echo-server
npm install -g laravel-echo-server
4.2 初始化laravel-echo-server
项目根目录运行打开终端;运行命令如下:
$ laravel-echo-server init
? Do you want to run this server in development mode? No
? Which port would you like to serve from? 6001
? Which database would you like to use to store presence channel members? redis
? Enter the host of your Laravel authentication server. http://localhost
? Will you be serving on http or https? http
? Do you want to generate a client ID/Key for HTTP API? No
? Do you want to setup cross domain access to the API? No
Configuration file saved. Run laravel-echo-server start to run server.
根目录生成配置文件laravel-echo-server.json 配置文件,默认配置为:
{
"authHost": "http://localhost",
"authEndpoint": "/broadcasting/auth",
"clients": [],
"database": "redis",
"databaseConfig": {
"redis": {},
"sqlite": {
"databasePath": "/database/laravel-echo-server.sqlite"
}
},
"devMode": false,
"host": null,
"port": "6001",
"protocol": "http",
"socketio": {},
"sslCertPath": "",
"sslKeyPath": "",
"sslCertChainPath": "",
"sslPassphrase": "",
"subscribers": {
"http": true,
"redis": true
},
"apiOriginAllow": {
"allowCors": false,
"allowOrigin": "",
"allowMethods": "",
"allowHeaders": ""
}
}
devMode 修改为 true
4.3 启动laravel-echo-server
$ laravel-echo-server start
L A R A V E L E C H O S E R V E R
version 1.5.0
⚠ Starting server in DEV mode...
✔ Running at localhost on port 6001
✔ Channels are ready.
✔ Listening for http events...
✔ Listening for redis events...
Server ready!
5.
laravel-echo收听到广播
5.1 安装laravel-echo
由于前端使用的是 laravel-echo来收听广播,我们选择的底层实现方式是socket.io。所以首先我们要在package.json中添加 laravel-echo 和 socket.io的依赖
$ npm i --save socket.io-client
$ npm i --save laravel-echo
安装laravel-mix:
npm install --save-dev laravel-mix
npm install --unsafe-perm=true --allow-root
5.2 添加测试页面
打开 /resources/assets/js/bootstrap.js 你会发现在这个文件的结尾已经预先写上了 laravel-echo 的使用例子,在文件底部添加如下代码:
import Echo from 'laravel-echo'
window.io = require('socket.io-client');
window.Echo = new Echo({
broadcaster: 'socket.io',
host: window.location.hostname + ':6001'
});
没问题再运行以下命令来编译js,css文件:
npm run dev
这样页面在初始化的时候就会连接上laravel-echo-server。
bootstrap.js 会被 resources/assets/js/app.js 调用。app.js又通过以下引用在页面被调用:
修改文件resources/views/welcome.blade.php
内容如下:
BroadcastService
Broadcast Service
{{----}}
js代码的意思是收听news通道内的News事件对象,将接收到的事件在控制台打印出来
接下来就是访问页面去访问数据了
总共需要开启三个终端:
终端1:启动队列进程
php artisan queue:work
终端2:开启laravel-echo-server服务端服务
laravel-echo-server start
终端3:运行php artisan命令触发广播事件(只是测试使用,项目中根据业务需求直接触发广播事件)
php artisan bignews
好了,去项目首页去测试一下项目广播事件运行如何,这里就自行省略的,如果哪里又不合适的请及时提出,进行改正,也感谢下边这位博主的帮助
参考文章:Laravel Broadcasting广播机制(Redis + socket.io)-学习实例