與ThinkPHP等框架結(jié)合
使用GatewayWorker時(shí)開(kāi)發(fā)者最關(guān)心的是如何與現(xiàn)有mvc框架(ThinkPHP Yii laravel等)整合,以下是官方推薦的整合方式。見(jiàn)示意圖:
總體原則:
現(xiàn)有mvc框架項(xiàng)目與GatewayWorker獨(dú)立部署互不干擾
所有的業(yè)務(wù)邏輯都由網(wǎng)站頁(yè)面post/get到mvc框架中完成
GatewayWorker不接受客戶(hù)端發(fā)來(lái)的數(shù)據(jù),即GatewayWorker不處理任何業(yè)務(wù)邏輯,GatewayWorker僅僅當(dāng)做一個(gè)單向的推送通道
僅當(dāng)mvc框架需要向?yàn)g覽器主動(dòng)推送數(shù)據(jù)時(shí)才在mvc框架中調(diào)用Gateway的API GatewayClient完成推送。
GatewayClient安裝
參考地址 https://github.com/walkor/GatewayClient
具體實(shí)現(xiàn)步驟
1、網(wǎng)站頁(yè)面建立與GatewayWorker的websocket連接
2、GatewayWorker發(fā)現(xiàn)有頁(yè)面發(fā)起連接時(shí),將對(duì)應(yīng)連接的client_id發(fā)給網(wǎng)站頁(yè)面
3、網(wǎng)站頁(yè)面收到client_id后觸發(fā)一個(gè)ajax請(qǐng)求(假設(shè)是bind.php
)將client_id發(fā)到mvc后端
4、mvc后端bind.php
收到client_id后利用GatewayClient調(diào)用Gateway::bindUid($client_id, $uid)
將client_id與當(dāng)前uid(用戶(hù)id或者客戶(hù)端唯一標(biāo)識(shí))綁定。如果有群組、群發(fā)功能,也可以利用Gateway::joinGroup($client_id, $group_id)
將client_id加入到對(duì)應(yīng)分組
5、頁(yè)面發(fā)起的所有請(qǐng)求都直接post/get到mvc框架統(tǒng)一處理,包括發(fā)送消息
6、mvc框架處理業(yè)務(wù)過(guò)程中需要向某個(gè)uid或者某個(gè)群組發(fā)送數(shù)據(jù)時(shí),直接調(diào)用GatewayClient的接口Gateway::sendToUid Gateway::sendToGroup
等發(fā)送即可
示例代碼
GatewayWorker中Events.php代碼(只有個(gè)onConnect回調(diào)設(shè)置)
<?php
use \GatewayWorker\Lib\Gateway;
class Events
{
// 當(dāng)有客戶(hù)端連接時(shí),將client_id返回,讓mvc框架判斷當(dāng)前uid并執(zhí)行綁定
public static function onConnect($client_id)
{
Gateway::sendToClient($client_id, json_encode(array(
'type' => 'init',
'client_id' => $client_id
)));
}
// GatewayWorker建議不做任何業(yè)務(wù)邏輯,onMessage留空即可
public static function onMessage($client_id, $message)
{
}
}
網(wǎng)站頁(yè)面js片段
/**
* 與GatewayWorker建立websocket連接,域名和端口改為你實(shí)際的域名端口,
* 其中端口為Gateway端口,即start_gateway.php指定的端口。
* start_gateway.php 中需要指定websocket協(xié)議,像這樣
* $gateway = new Gateway(websocket://0.0.0.0:7272);
*/
ws = new WebSocket("ws://your_domain.com:7272");
// 服務(wù)端主動(dòng)推送消息時(shí)會(huì)觸發(fā)這里的onmessage
ws.onmessage = function(e){
// json數(shù)據(jù)轉(zhuǎn)換成js對(duì)象
var data = eval("("+e.data+")");
var type = data.type || '';
switch(type){
// Events.php中返回的init類(lèi)型的消息,將client_id發(fā)給后臺(tái)進(jìn)行uid綁定
case 'init':
// 利用jquery發(fā)起ajax請(qǐng)求,將client_id發(fā)給后端進(jìn)行uid綁定
$.post('./bind.php', {client_id: data.client_id}, function(data){}, 'json');
break;
// 當(dāng)mvc框架調(diào)用GatewayClient發(fā)消息時(shí)直接alert出來(lái)
default :
alert(e.data);
}
};
mvc后端uid綁定代碼片段
bind.php (利用GatewayClient綁定)
<?php
//加載GatewayClient。關(guān)于GatewayClient參見(jiàn)本頁(yè)面底部介紹
require_once '/your/path/GatewayClient/Gateway.php';
// GatewayClient 3.0.0版本開(kāi)始要使用命名空間
use GatewayClient\Gateway;
// 設(shè)置GatewayWorker服務(wù)的Register服務(wù)ip和端口,請(qǐng)根據(jù)實(shí)際情況改成實(shí)際值(ip不能是0.0.0.0)
Gateway::$registerAddress = '127.0.0.1:1236';
// 假設(shè)用戶(hù)已經(jīng)登錄,用戶(hù)uid和群組id在session中
$uid = $_SESSION['uid'];
$group_id = $_SESSION['group'];
// client_id與uid綁定
Gateway::bindUid($client_id, $uid);
// 加入某個(gè)群組(可調(diào)用多次加入多個(gè)群組)
Gateway::joinGroup($client_id, $group_id);
mvc后端發(fā)消息代碼片段
send_message.php (利用GatewayClient發(fā)送)
<?php
//加載GatewayClient。關(guān)于GatewayClient參見(jiàn)本頁(yè)面底部介紹
require_once '/your/path/GatewayClient/Gateway.php';
// GatewayClient 3.0.0版本開(kāi)始要使用命名空間
use GatewayClient\Gateway;
// 設(shè)置GatewayWorker服務(wù)的Register服務(wù)ip和端口,請(qǐng)根據(jù)實(shí)際情況改成實(shí)際值(ip不能是0.0.0.0)
Gateway::$registerAddress = '127.0.0.1:1236';
// 向任意uid的網(wǎng)站頁(yè)面發(fā)送數(shù)據(jù)
Gateway::sendToUid($uid, $message);
// 向任意群組的網(wǎng)站頁(yè)面發(fā)送數(shù)據(jù)
Gateway::sendToGroup($group, $message);
注意
以上僅是mvc框架與GatewayWorker官方推薦的結(jié)合方式,并不是強(qiáng)制使用此方式,開(kāi)發(fā)者可以自由變化選擇結(jié)合方式以適應(yīng)自己的業(yè)務(wù)需求。
當(dāng)然也可以采用客戶(hù)端與GatewayWorker直接雙向通訊的方式完成業(yè)務(wù)通訊。
關(guān)于GatewayClient
源碼:
https://github.com/walkor/GatewayClient
注意:
如果GatewayClient和GatewayWorker不是在同一臺(tái)服務(wù)器上,則需要先將start_gateway.php中的lanIp改成當(dāng)前服務(wù)器的內(nèi)網(wǎng)ip(如果不在一個(gè)內(nèi)網(wǎng)可改成公網(wǎng)ip)。
如果GatewayClient和GatewayWorker在同一臺(tái)服務(wù)器上運(yùn)行,則不用做任何更改,直接按照示例使用GatewayClient即可。
通過(guò)GatewayClient發(fā)送的數(shù)據(jù)不會(huì)經(jīng)過(guò)Event.php,而是直接經(jīng)由Gateway進(jìn)程轉(zhuǎn)發(fā)給客戶(hù)端。
GatewayClient無(wú)法接收客戶(hù)端發(fā)來(lái)的數(shù)據(jù)。
客戶(hù)端使用示例
require_once '/your/path/GatewayClient/Gateway.php';
/**
* gatewayClient 3.0.0及以上版本加了命名空間
* 而3.0.0以下版本不需要use GatewayClient\Gateway;
**/
use GatewayClient\Gateway;
/**
*====這個(gè)步驟是必須的====
*這里填寫(xiě)Register服務(wù)的ip和Register端口,注意端口不是gateway端口
*ip不能是0.0.0.0,端口在start_register.php中可以找到
*這里假設(shè)GatewayClient和Register服務(wù)都在一臺(tái)服務(wù)器上,ip填寫(xiě)127.0.0.1。
*如果不在一臺(tái)服務(wù)器則填寫(xiě)真實(shí)的Register服務(wù)的內(nèi)網(wǎng)ip(或者外網(wǎng)ip)
**/
Gateway::$registerAddress = '127.0.0.1:1236';
// 以下是調(diào)用示例,接口與GatewayWorker環(huán)境的接口一致
// 接口具體使用方法見(jiàn)《Lib\Gateway類(lèi)提供的接口》一章
// 注意除了不支持sendToCurrentClient和closeCurrentClient方法
// 其它方法都支持
Gateway::sendToAll($data);
Gateway::sendToClient($client_id, $data);
Gateway::closeClient($client_id);
Gateway::isOnline($client_id);
Gateway::bindUid($client_id, $uid);
Gateway::isUidOnline($uid);
Gateway::getClientIdByUid($uid);
Gateway::unbindUid($client_id, $uid);
Gateway::sendToUid($uid, $data);
Gateway::joinGroup($client_id, $group);
Gateway::sendToGroup($group, $data);
Gateway::leaveGroup($client_id, $group);
Gateway::getClientCountByGroup($group);
Gateway::getClientSessionsByGroup($group);
Gateway::getAllClientCount();
Gateway::getAllClientSessions();
Gateway::setSession($client_id, $session);
Gateway::updateSession($client_id, $session);
Gateway::getSession($client_id);
...