Laravel 5.2 使用 swoole websocket ,事件广播不成功?

app/Console/Commands/Swoole.php

<?php
namespace App\Console\Commands;
use App\Handlers\SwooleHandler;
use Illuminate\Console\Command;


class Swoole extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'swoole {action}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'swoole socket';

    protected $ws;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command.
     *
     * @return mixed
     */
    public function handle()
    {
        $action = $this->argument('action');
        $this->ws = new \swoole_websocket_server( "http://" .env('SOCKET_DOMAIN'), env('SOCKET_PORT') );
        $this->ws->set(['worker_num' => env('SOCKET_WORKER_NUM')]);
        switch ($action) {
            case 'start':
                $handler = new SwooleHandler();
                $this->ws->on('Open', [$handler, 'onOpen']);
                $this->ws->on('Message', [$handler, 'onMessage']);
                $this->ws->on('Close', [$handler, 'onClose']);
                $this->ws->start();
                break;
            case 'reload':
                $this->ws->reload();
                break;
            case 'stop':
                $this->ws->stop();
                break;
        }

    }
}

app/Handlers/SwooleHandler.php

<?php
namespace App\Handlers;

use LRedis;
use App\Models\Message;

class SwooleHandler
{
    public function onOpen($ws, $request)
    {
        $user_id = $request->get['user_id'];
        echo "client - {$user_id} is opened\n";
        LRedis::hSet('FRONT_USERS', $user_id, $request->fd);
    }

    public function onMessage($ws, $frame)
    {
        $user_id = $frame->data;
        $fd = LRedis::hGet('FRONT_USERS', $user_id);
        echo "client - {$fd} is send\n";
        $num = Message::query()->where('user_id',$user_id)->count();
        $ws->push($fd, $num);
    }

    public function onClose($ws, $fd)
    {
        echo "client - {$fd} is closed\n";
        $all = LRedis::hGetAll('FRONT_USERS');
        foreach ($all as $key => $val) {
            if ($fd == LRedis::hGet('FRONT_USERS', $key)) {
                LRedis::hDel('FRONT_USERS', $key);
                echo "del {$key}\n";
            }
        }
    }

}

app/Events/MessageEvent.php

<?php

namespace App\Events;

use App\Models\Message;
use App\Events\Event;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class MessageEvent extends Event implements ShouldBroadcast
{
    use SerializesModels;
    public $user_id;
    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($from_user_id, $user_id, $content)
    {
        $this->model = new Message();
        $this->from_user_id = $from_user_id;
        $this->user_id = $user_id;
        $this->content = $content;
    }

    /**
     * Get the channels the event should be broadcast on.
     *
     * @return array
     */
    public function broadcastOn()
    {
        return ['message-channel'];
    }
}

app/Listeners/MessageListener.php

<?php
namespace App\Listeners;

use App\Events\MessageEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;

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

    /**
     * Handle the event.
     *
     * @param  MessageEvent  $event
     * @return void
     */
    public function handle(MessageEvent $event)
    {
        $model = $event->model;
        $model->from_user_id = $event->from_user_id;
        $model->user_id = $event->user_id;
        $model->content = $event->content;
        $model->save();
    }
}

app/Providers/EventServiceProvider.php

<?php
namespace App\Providers;

use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * 事件侦听器映射到应用程序
     *
     * @var array
     */
    protected $listen = [
        // 站内信事件监听
        'App\Events\MessageEvent' => [
            'App\Listeners\MessageListener',
        ],
    ];

    /**
     * Register any other events for your application.
     *
     * @param  \Illuminate\Contracts\Events\Dispatcher  $events
     * @return void
     */
    public function boot(DispatcherContract $events)
    {
        parent::boot($events);
    }
}

前台模板

<!doctype html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>OA首页</title>
</head>
<body>
    <div style="width: 300px;margin: 100px auto;">
        <h1>Hi, {auth('front')->user()->name}</h1>
        <a href="{url('auth/logout')}">Logout</a>
    </div>
    <script type="text/javascript">
        var exampleSocket = new WebSocket("ws://{env('SOCKET_DOMAIN')}:{env('SOCKET_PORT')}?user_id={auth('front')->user()->id}");
        exampleSocket.onopen = function (event) {
            exampleSocket.send({auth('front')->user()->id});
        };
        exampleSocket.onmessage = function (event) {
            console.log(event.data);
        }
    </script>
</body>
</html>

运行 php artisan swoole start,前台页面第一次加载的时候,websocket 链接的 onopen, onmessage, onclose 都是可以正常运行的。

Mac-Pro:xxx.com xxx$ php artisan swoole start
client - 22 is opened
client - 1 is send
client - 1 is closed

但是执行 \Illuminate\Support\Facades\Event::fire(new \App\Events\MessageEvent($from_user_id, $user_id, $content)) 触发事件的时候,前台页面onmessage里面不能输出最新的数据。。求大神指教。谢谢!

maokeyang
修改的评论也不能少于六个字哦!