
app/Console/Commands/Swoole.php
<?php namespace App\Console\Commands; use App\Handlers\SwooleHandler; use Illuminate\Console\Command; class Swoole extends Commad { /** * 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 里面不能输出最新的数据。。求大神指教。谢谢!
1 torbrowserbridge 2017 年 5 月 25 日 0. MessageListener::handle() 的作用是什么?执行了吗? 1. 广播驱动器是 Redis 吗?没看到在哪里订阅 channel 的呢? 2. 广播执行了吗?你可能需要 listen queue 来执行队列任务。 |
2 anai1943 OP @torbrowserbridge 0. MessageListener::handle() 执行了,是将 message 数据写入数据库 1. 广播驱动是 redis,订阅 channel 不明白怎么写。。 2. 运行 php artisan queue:listen 显示 Processed: Illuminate\Broadcasting\BroadcastEvent |
3 torbrowserbridge 2017 年 5 月 26 日 1. 写入数据库的目的是?为了统计 count ? 2. 你这段没实现订阅。 3. “运行 php artisan queue:listen 显示 Processed: Illuminate\Broadcasting\BroadcastEvent ” 这里证明 event 被广播出去了。 4. 可以在 redis 命令行中输入:psubscribe * 来实现订阅全部 channel。看看当事件被广播后,终端是否有对应的输出。 5. 如果 4 正常输出,尝试在 swoole 中实现 redis 订阅,然后将相应的结果写回对应的 fd |