依赖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服务连接参数

定义一个被广播的事件

<?phpnamespaceApp\Events;useApp\Events\Event;useIlluminate\Queue\SerializesModels;useIlluminate\Contracts\Broadcasting\ShouldBroadcast;useIlluminate\Support\Facades\Session;classMessageBroadcastEventextendsEventimplementsShouldBroadcast{useSerializesModels;public$users;public$message=array();protected$channel;/***Createaneweventinstance.**@returnvoid*/publicfunction__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-dH:i:s',strtotime($message['created_at'])));$this->channel=$channel;}/***Getthechannelstheeventshouldbebroadcaston.*广播到哪个频道*@returnarray*/publicfunctionbroadcastOn(){return[$this->channel];}}

默认情况下,Event中的所有public属性都会被序列化后广播。上面的例子中就是$users, $message 两个属性。也可以

使用broadcastWith这个方法,明确的指出要广播什么数据。例如:

publicfunctionbroadcastWith(){return['message'=>$this->message];}

Redis和Websocket服务器

依赖的就是redis的sub/pub功能

启动一个node websocket服务器来和client通信,我们使用socket.io

node 服务端代码 保存为 index.js 放在node服务目录

varapp=require('http').createServer(handler);vario=require('socket.io')(app);varRedis=require('ioredis');varredis=newRedis('6379','192.168.10.10');//连接redis服务器//监听客户端端口这里是6001app.listen(6001,function(){console.log('Serverisrunning!');});functionhandler(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);});

客户端代码,只要客户端需要被广播的页面正确引用 node socket.io 模块客户端js文件(自行将这个客户端模块文件放到项目public目录)

<scriptsrc="js/socket.io/node_modules/socket.io-client/socket.io.js"></script>//客户端也使用socket.io,测试代码:控制台打印输出//连接socket服务器varsocket=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、控制器中直接调用

//发送给哪些用户id。这里定义消息接收用户,是在前台用于检测登陆用户是否在这个数组中,存在则做出相应的即时提醒。//注意:其实广播消息都会被发送到对应的频道的。$users=array(1,2);//这里可以保存发送消息到messages表$message=newMessage();$message->title='您的店铺有一条新销售单';$message->content='您的店铺有一条新销售单,单号1000000';$message->message_type_id=1;$message->status=0;$message->url='http://www.xxx.com';$message->save();//保存发送用户到user_message表$userMessage=array();$time=date("Y-m-dH:i:s");foreach($usersas$user){$tmp=array('created_at'=>$time,'updated_at'=>$time,'user_id'=>$user,'message_id'=>$message->id,'read'=>0);$userMessage[]=$tmp;}UserMessage::insert($userMessage);//广播的频道//我们以店铺id来标识频道,这样前端用户页面也根据店铺id标识来收听自己店铺频道,就能做到店铺广播消息消息只能广播到本店铺用户$channel='channel-'.Session::get('shop')->id;//$channel='channel-system';//其他频道//$response=event(newMessageBroadcastEvent($users,$message,$channel));Event::fire(newMessageBroadcastEvent($users,$message,$channel));//这两种方式都可以触发事件

2、路由中直接调用

//示例代码Route::get('/event',function(){Event::fire(new\App\Events\SomeEvent(3));return"helloworld";});

使用:

必须开启 node websocket 服务端。我在本机windows下C盘安装node,服务端代码就放在这个目录下,进入cmd

终端,执行命令,node index.js 启动服务端。

打开包含有 socket.io 代码的客户端页面,等待被广播

触发我们的后台广播事件(执行相应的控制器代码)