GatewayWorker 結合 Laravel 使用的簡單案例,重點是在Laravel中使用GatewayClient發送消息php
主要流程:GatewayWorker主要負責推送消息給客戶端但不接受客戶端數據,Laravel主要負責接受客戶端數據並處理業務邏輯,而後使用GatewayClient推送數據,css
示意圖拿一個官方圖片哈 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.htmlhtml
跟Laravel結合使用的優勢:jquery
1,當 GatewayWorker服務運行時,修改了Laravel業務代碼,直接推送業務相關代碼到服務器上便可,不用重啓GatewayWorker服務;laravel
2,能夠盡情使用Laravel提供的各類便利工具處理數據和業務邏輯;git
整個項目壓縮文件太大不便上傳,接下來直接貼代碼咯,github
本地windows使用步驟:web
1,啓動GatewayWorker,雙擊 start_for_win.batajax
2,新建一個虛擬域名路徑指定到該項目public目錄json
3,開兩個瀏覽器頁面就能互發消息了,以下面兩個效果圖,
效果圖:
項目結構:
ChatServer目錄下的4個start_*.php文件是直接複製的官方demo https://github.com/walkor/workerman-chat/tree/master/Applications/Chat
composer.json 的 require 部分
"require": { "php": ">=7.0.0", "fideloper/proxy": "~3.3", "laravel/framework": "5.5.*", "laravel/tinker": "~1.0", "workerman/gateway-worker" : ">=3.0.0", "workerman/gatewayclient": "^3.0" },
start_for_win.bat 本地windows啓動腳本
php app\ChatServer\start_register.php app\ChatServer\start_web.php app\ChatServer\start_gateway.php app\ChatServer\start_businessworker.php
pause
start.php 服務器上的啓動腳本
<?php /** * run with command * php start.php start */ ini_set('display_errors', 'on'); use Workerman\Worker; if(strpos(strtolower(PHP_OS), 'win') === 0) { exit("start.php not support windows, please use start_for_win.bat\n"); } // 檢查擴展 if(!extension_loaded('pcntl')) { exit("Please install pcntl extension. See http://doc3.workerman.net/appendices/install-extension.html\n"); } if(!extension_loaded('posix')) { exit("Please install posix extension. See http://doc3.workerman.net/appendices/install-extension.html\n"); } // 標記是全局啓動 define('GLOBAL_START', 1); require_once __DIR__ . '/vendor/autoload.php'; // 加載全部application/*/start.php,以便啓動全部服務 foreach(glob(__DIR__.'/app/ChatServer/start*.php') as $start_file) { require_once $start_file; } // 運行全部服務 Worker::runAll();
Events.php 參考 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.html
<?php /** * 用於檢測業務代碼死循環或者長時間阻塞等問題 * 若是發現業務卡死,能夠將下面declare打開(去掉//註釋),並執行php start.php reload * 而後觀察一段時間workerman.log看是否有process_timeout異常 */ //declare(ticks=1); use \GatewayWorker\Lib\Gateway; class Events { // 當有客戶端鏈接時,將client_id返回,讓mvc框架判斷當前uid並執行綁定 public static function onConnect($client_id) { Gateway::sendToClient($client_id, json_encode(array( 'type' => 'init', 'client_id' => $client_id ))); } // GatewayWorker建議不作任何業務邏輯,onMessage留空便可 public static function onMessage($client_id, $message) { } }
IndexController.php 發送消息用的控制器 參考 http://www.workerman.net/gatewaydoc/work-with-other-frameworks/README.html
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use GatewayClient\Gateway; class IndexController extends Controller { public function __construct() { Gateway::$registerAddress = '127.0.0.1:1236'; } /** * web客戶端 * @param string $uid * @param string $to_uid * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View */ public function client() { return view('client'); } /** * 綁定uid * @return mixed */ public function bind() { // 假設用戶已經登陸,用戶uid和羣組id在session中 $uid = request('uid'); $client_id = request('client_id'); $res = request()->all(); $res['type'] = 'bind'; $res['time'] = date('H:i:s'); // client_id與uid綁定 Gateway::bindUid($client_id, $uid); Gateway::sendToUid($uid, json_encode($res)); return response()->json($res); } /** * 發送消息 * @return mixed */ public function send() { $uid = request('uid'); $to_uid = request('to_uid'); $res = request()->all(); $res['type'] = 'send'; $res['time'] = date('H:i:s'); // 向任意uid的網站頁面發送數據 Gateway::sendToUid($uid, json_encode($res)); Gateway::sendToUid($to_uid, json_encode($res)); return response()->json($res); } }
web.php 路由
<?php /* |-------------------------------------------------------------------------- | Web Routes |-------------------------------------------------------------------------- | | Here is where you can register web routes for your application. These | routes are loaded by the RouteServiceProvider within a group which | contains the "web" middleware group. Now create something great! | */ Route::get('/', function () { return view('welcome'); }); Route::match(['post', 'get'], 'index/index/{uid}/{to_uid}', 'IndexController@client'); Route::match(['post', 'get'], 'index/client/{uid}/{to_uid}', 'IndexController@client'); Route::match(['post', 'get'], 'index/bind', 'IndexController@bind'); Route::match(['post', 'get'], 'index/send', 'IndexController@send');
client.blade.php web客戶端視圖
<html> <head> <title>{{ request('uid') }} => {{ request('to_uid') }}</title> <link href="https://cdn.bootcss.com/normalize/8.0.0/normalize.css" rel="stylesheet"> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.js"></script> <script src="https://cdn.bootcss.com/json5/0.5.1/json5.js"></script> <style> * { padding: 0; margin: 0; } .chat-main { width: 600px; margin: 30px auto; box-shadow: 0 0 1px gray; border: 1px solid gray; line-height: 1.5em; } .chat-header { border-bottom: 1px solid gray; padding: 5px 15px; } .chat-log { height: 200px; overflow-y: auto; border-bottom: 1px solid gray; padding: 5px 15px; } .chat-log dl { margin: 15px 0; } .chat-log dl dd { display: inline-block; border: 1px solid gray; padding: 5px 15px; border-radius: 10px; border-top-left-radius: 0; } .chat-log dl.me dd { border-radius: 10px; border-top-right-radius: 0; } .chat-log dl.me { text-align: right; } .chat-log dl.me dd { text-align: left; } .user-link { float: right; } .user-link a { margin-left: 5px; } .hide { display: none; } .inline-block { display: inline-block; } .btn { text-align: right; padding: 5px 15px 15px; } #btn-send { display: inline-block; background: white; border: 1px solid gray; line-height: 2em; padding: 0 2em; outline: none; } #btn-send:focus { background: white; border-color: green; } #message { display: block; width: 570px; height: 100px; margin: 15px auto 0; border: 1px solid gray; overflow-x: hidden; overflow-y: auto; resize: none; outline: none; padding: 10px; } #message:focus { border-color: green; } .chat-body > .tpl { display: none; } </style> </head> <body> <div class="hide"> bind<input type="text" id="bind" value="{{ url('index/bind') }}"><br> send<input type="text" id="send" value="{{ url('index/send') }}"><br> </div> <div class="chat-main"> <div class="chat-header"> <div class="chat-title inline-block"> {{ request('uid') }} => {{ request('to_uid') }} </div> <div class="user-link inline-block"> <span class="inline-block">模擬用戶</span> <a class="inline-block" href="{{ url('index/index',['uid'=>1111,'to_uid'=>2222]) }}">1111</a> <a class="inline-block" href="{{ url('index/index',['uid'=>2222,'to_uid'=>1111]) }}" target="_blank">2222</a> </div> </div> <div class="chat-body"> <div class="chat-log"> </div> <dl class="tpl"> <dt>1111(12:00:00)</dt> <dd>aaaabbbbbb</dd> </dl> </div> <div class="chat-footer"> <form action="" id="form"> <div class="hide"> cliend_id<input type="text" name="client_id" id="client_id" value="{{ request('uid') }}"><br> uid<input type="text" name="uid" id="uid" value="{{ request('uid') }}"><br> to_uid<input type="text" name="to_uid" value="{{ request('to_uid') }}"><br> </div> <textarea name="message" id="message" cols="30" rows="10"></textarea> <div class="btn"> <button type="button" id="btn-send">發 送</button> </div> </form> </div> </div> <script> /** * 與GatewayWorker創建websocket鏈接,域名和端口改成你實際的域名端口, * 其中端口爲Gateway端口,即start_gateway.php指定的端口。 * start_gateway.php 中須要指定websocket協議,像這樣 * $gateway = new Gateway(websocket://0.0.0.0:7272); */ ws = new WebSocket("ws://127.0.0.1:7272"); // 服務端主動推送消息時會觸發這裏的onmessage ws.onmessage = function (e) { // json數據轉換成js對象 var data = JSON5.parse(e.data); var type = data.type || ''; switch (type) { // Events.php中返回的init類型的消息,將client_id發給後臺進行uid綁定 case 'init': $('#client_id').val(data.client_id); // 利用jquery發起ajax請求,將client_id發給後端進行uid綁定 $.get($('#bind').val(), $('#form').serialize(), function (res) { console.log('bind', res); }, 'json'); break; case 'send': var $tpl = $('.chat-body>.tpl').clone().show(); if (data.uid == $('#uid').val()) { $tpl.find('dt').html('(' + data.time + ') ' + data.uid); $tpl.addClass('me') } else { $tpl.find('dt').html(data.uid + ' (' + data.time + ')'); } $tpl.find('dd').html(data.message.replace(/\n/gim, '<br>')); $('.chat-log').append($tpl); scrollBottom(); break; // 當mvc框架調用GatewayClient發消息時直接alert出來 default: console.log('default', e.data); } }; $('#form').submit(function (e) { return false; }); var isScrollBottom = true; function scrollBottom(){ if (isScrollBottom) { $('.chat-log').scrollTop($('.chat-log')[0].scrollHeight); } } $('#btn-send').click(function (e) { if ($.trim($('#message').val())) { $.get($('#send').val(), $('#form').serialize(), function (res) { console.log('send', res); $('#message').val(''); scrollBottom(); }, 'json'); } }); $('.chat-log').scroll(function (e) { var outerHeight = $(this).outerHeight(); var scrollTop = $(this).scrollTop(); var scrollHeight = $(this)[0].scrollHeight; if (outerHeight + scrollTop >= scrollHeight - 15) { isScrollBottom = true; } else { isScrollBottom = false; } }) </script> </body> </html>
==============================================
本文連接 http://www.javashuo.com/article/p-vpjlgdej-dx.html
==============================================