依赖 laravel(predis)、 redis、 nodejs(ioredis,socket.io)
1、修改config\app.php
providers数组 添加 ‘Illuminate\Broadcasting\BroadcastServiceProvider’,
2、修改广播驱动方式为 config\broadcasting.php
‘default’ => env(‘BROADCAST_DRIVER’, ‘redis’), 改为redis驱动
使用redis作为php和js的通信方式。
3、配置config\database.php
配置redis服务连接参数
定义一个被广播的事件
<?php
namespace App\Events;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Support\Facades\Session;
class MessageBroadcastEvent extends Event implements ShouldBroadcast
{
use SerializesModels;
public $users;
public $message = array();
protected $channel;
public function __construct($users, $message, $channel)
{
$this->users = $users;
$this->message = array(
'id' => $message['id'],
'title' => $message['title'],
'content' => $message['content'],
'url' => $message['url'],
'time' => date('m-d H:i:s', strtotime($message['created_at']))
);
$this->channel = $channel;
}
public function broadcastOn()
{
return [$this->channel];
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
默认情况下,Event中的所有public属性都会被序列化后广播。上面的例子中就是users,message 两个属性。也可以
使用broadcastWith这个方法,明确的指出要广播什么数据。例如:
public function broadcastWith(){
return ['message ' => $this->message ];
}
Redis和Websocket服务器
依赖的就是redis的sub/pub功能
启动一个node websocket服务器来和client通信,我们使用socket.io
node 服务端代码 保存为 index.js 放在node服务目录
var app = require('http').createServer(handler);
var io = require('socket.io')(app);
var Redis = require('ioredis');
var redis = new Redis('6379', '192.168.10.10');
app.listen(6001, function() {
console.log('Server is running!');
});
function handler(req, res) {
res.writeHead(200);
res.end('');
}
io.on('connection', function(socket) {
console.log('connected');
});
redis.psubscribe('*', function(err, count) {
console.log(count);
});
redis.on('pmessage', function(subscribed, channel, message) {
console.log(subscribed);
console.log(channel);
console.log(message);
message = JSON.parse(message);
io.emit(channel + ':' + message.event, message.data);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
客户端代码,只要客户端需要被广播的页面正确引用 node socket.io 模块客户端js文件(自行将这个客户端模块文件放到项目public目录)
<script src="js/socket.io/node_modules/socket.io-client/socket.io.js"></script>
var socket = io('http://localhost:6001');
socket.on('connection', function (data) {
console.log(data);
});
socket.on('channel-{{ Session::get('shop')->id }}:App\\Events\\MessageBroadcastEvent', function(data) {
console.log(message);
});
socket.on('channel-system:App\\Events\\MessageBroadcastEvent', function(data){
console.log(data);
});
console.log(socket);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
项目中触发事件
在控制器或者在路由匿名函数中都可以直接调用广播事件
1、控制器中直接调用
$users = array(1, 2);
$message = new Message();
$message->title = '您的店铺有一条新销售单';
$message->content = '您的店铺有一条新销售单,单号1000000';
$message->message_type_id = 1;
$message->status = 0;
$message->url = 'http://www.xxx.com';
$message->save();
$userMessage = array();
$time = date("Y-m-d H:i:s");
foreach ($users as $user) {
$tmp = array(
'created_at' =>$time,
'updated_at' =>$time,
'user_id' =>$user,
'message_id' =>$message->id,
'read' =>0
);
$userMessage[] = $tmp;
}
UserMessage::insert($userMessage);
$channel = 'channel-' . Session::get('shop')->id;
Event::fire(new MessageBroadcastEvent($users, $message, $channel));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
2、路由中直接调用
Route::get('/event', function(){
Event::fire(new \App\Events\SomeEvent(3));
return "hello world";
});
使用:
必须开启 node websocket 服务端。我在本机windows下C盘安装node,服务端代码就放在这个目录下,进入cmd
终端,执行命令,node index.js 启动服务端。
打开包含有 socket.io 代码的客户端页面,等待被广播
触发我们的后台广播事件(执行相应的控制器代码)