Laravel5.7广播

#0 广播架构及相关概念

  • 本文使用Redis + socket.io 方案

  • 架构组件及涉及到的概念

    • laravel-echo-server:使用 socket.io 机制实现的 broadcasting 服务端
    • laravel-echolaravel-echolaravel broadcasting 的客户端。

    注意: laravel-echo 并不是 laravel-echo-server 专属的客户端, laravel-echo 有两种连接机制可以选:pushersocket.io 。 而 laravel-echo-server 是开发出来专门用于 socket.io 连接的服务端。如果你使用的是 pusher,那么不需要使用 laravel-echo-server ,但是你依然要使用 laravel-echo

    • Socket.IOwebsocket 的一种nodejs实现。laravel-echo 如果要使用socket.io 则需要先安装socket.io-client
    • Predisredis客户端的php实现,如果要使用redis作为广播机制的实现,则需要先安装 predis
    • Laravel Event:广播事件类
    • Laravel Queue:广播机制是基于queue机制来实现的
    • Redis Sub/PubRedis的订阅机制。laravel-echo-server本质上只是一个Redis订阅服务的订阅者。
  • 架构图

  • Laravel事件的广播机制流程:

    • Laravel通过 broadcasting 机制发布一个Event对象到Redis
    • Laravel Queue Worker 读取该Event对象,并使用RedisSub/Pub机制将该 Event对象发布出去
    • laravel-echo-server 通过 RedisSub/Pub机制收听到该 Event
    • 由于 laravel-echo 使用 socket.iolaravel-echo-server相连接。所以 laravel-echo 会通过socket.ioEvent对象发送给laravel-echo
    • laravel-echo解析通过 socket.io接收到的 Event对象
  • 广播事件种类:

    • public:谁都可以收听的广播
    • private:只有指定用户可以收到的广播
    • presence:不仅可以收听到跟你有关的广播,还可以跟别的用户互动,适合做聊天室

#1 让Laravel将Event发布到Redis

#1 建立广播服务

打开 config/app.php 找到 provides 属性,将 BroadcastServiceProvider 前的注释去掉

    //...
    'providers' => [
        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        //...
    ],
    //...
复制代码

#2 设置Redis连接

##.env文件
BROADCAST_DRIVER=redis
CACHE_DRIVER=redis
#QUEUE_CONNECTION=sync
QUEUE_CONNECTION=redis
SESSION_DRIVER=file
SESSION_LIFETIME=120
复制代码

#3 安装predis

composer require predis/predis
复制代码

#4 新建Event和Listener

php artisan make:event Backend/Poster/PosterEvent

php artisan make:listener Backend/Poster/PosterNotification
复制代码
<?php

namespace App\Events\Backend\Poster;

use App\Models\Poster\Poster;
use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class PosterEvent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $poster;

    public $action;

    public $broadcastQueue = 'default';

    /**
     * Create a new event instance.
     *
     * @param Poster $poster
     * @param string $action
     */
    public function __construct(Poster $poster, $action = 'created')
    {
        $this->poster = $poster;
        $this->action = $action;
    }

    /**
     * 事件的广播名称
     * #如果你使用了 broadcastAs 方法来自定义广播名称,你应当确保在你注册监听器时加上一个 . 的前缀
     * #这将指示 Echo 不要在事件之前添加应用程序的命名空间
     * @return string
     */
    public function broadcastAs() : string
    {
        return 'backend_poster';
    }

    /**
     * @return array
     */
    public function broadcastWith() : array
    {
        $url        = '';
        $msg        = '';
        if (in_array($this->action, ['created', 'updated'])) {
            $url    = route('b.poster.edit', $this->poster);
            $msg    = "海报☆{$this->poster->title}☆已" . ($this->action === 'created' ? '新增' : '更新') . '!';
        }
        if ($this->action === 'deleted') {
            $msg    = "海报☆{$this->poster->title}☆已删除!";
        }
        $data = [
            'total' => Poster::getActiveTotal(),
            'month' => Poster::getMonthActiveTotal(),
            'data'  => $this->poster,
            'url'   => $url,
            'msg'   => $msg,
        ];
        return $data;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('poster_room');
    }
}

复制代码
<?php

namespace App\Listeners\Backend\Poster;

use App\Events\Backend\Poster\PosterEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

class PosterNotification implements ShouldQueue
{
    /**
     * 任务将被发送到的队列的连接的名称
     * @var string
     */
    public $connection = 'redis';

    /**
     * 任务将被发送到的队列的名称
     * @var string
     */
    public $queue = 'default';

    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * @param PosterEvent $event
     */
    public function handle(PosterEvent $event)
    {
        //TODO
    }
}

复制代码

#5 设置广播路由

//routes/channels.php
Broadcast::channel('poster_room', function () {
    return true;
});
复制代码

2# 运行队列处理器,让Laravel Queue Worker消费Event

1# 安装 Supervisor

sudo apt-get install supervisor
复制代码

2# 配置 Supervisor

cd /etc/supervisor/conf.d/
sudo vim laravel-backend.conf
复制代码
[program:laravel-backend]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/top/artisan horizon
autostart=true
autorestart=true
user=locoroco
redirect_stderr=true
stdout_logfile=/home/locoroco/top-booking.com/worker.log
复制代码
sudo vim laravel-echo.conf
复制代码
[program:laravel-echo]
process_name=%(program_name)s_%(process_num)02d
directory=/var/www/top
command=laravel-echo-server start
autostart=true
autorestart=true
user=locoroco
redirect_stderr=true
stdout_logfile=/home/locoroco/top-booking.com/echo-server.log
复制代码

numprocs 会告诉 Supervisor 运行 8 个 queue:work 进程并且管理它们,当它们关闭时会将其自动重启

3# 启动 Supervisor

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start laravel-backend:*

##restart
sudo supervisorctl restart laravel-backend:*
复制代码

3# 让 laravel-echo-server 订阅Redis Sub

## 安装laravel-echo-server
npm install -g laravel-echo-server

## 初始化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
laravel-echo-server start
复制代码

4# 让laravel-echo收听到广播

// bootstrap.js
import Echo from "laravel-echo";
window.io = require('socket.io-client');

window.Echo = new Echo({
    broadcaster: 'socket.io',
    host: window.location.hostname + ':6001'
});

//webpack.mix.js
const { mix } = require('laravel-mix');

mix.sass('resources/backend/sass/app.scss', 'public/css/iframe/backend.css')
    .js('resources/backend/js/app.js','public/js/iframe/backend/app.js');
    
复制代码

package.json

{
    "private": true,
    "scripts": {
        "dev": "npm run development",
        "development": "NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
        "watch": "npm run development -- --watch",
        "watch-poll": "npm run watch -- --watch-poll",
        "watch-mobile": "npm run watch-poll -- --env.mobile",
        "watch-backend": "npm run watch-poll -- --env.backend",
        "watch-web": "npm run watch-poll -- --env.web",
        "watch-mobile1": "npm run watch-poll -- --env.mobile1",
        "hot": "NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
        "prod": "npm run production",
        "production": "NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
    },
    "devDependencies": {
        "axios": "^0.18.0",
        "babel-plugin-syntax-dynamic-import": "^6.18.0",
        "browser-sync": "^2.26.3",
        "browser-sync-webpack-plugin": "2.0.1",
        "cross-env": "^5.1",
        "laravel-mix": "^2.0",
        "lodash": "^4.17.5",
        "vue": "^2.5.17"
    },
    "dependencies": {
        "css-loader": "^2.0.0",
        "sass-loader": "^7.1.0",
        "laravel-echo": "^1.5.1",
        "socket.io-client": "^2.2.0",
        "toastr": "^2.1.4",
        "vue-axios": "^2.1.4",
        "vue-router": "^3.0.2",
        "vuex": "^3.0.1"
    }
}

复制代码

编译

npm install

##清空缓存
##npm cache verify  

npm run prod
复制代码

视图页面引入

<script src="{{asset('js/iframe/backend/app.js')}}"></script>
<script>
//recieve poster-room message
Echo.channel('poster_room')
	.listen('.backend_poster', (e) => {
	    //TODO
		console.log(e);
	});
</script>
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值