workerman怎么實(shí)現(xiàn)分組群聊

workerman怎么實(shí)現(xiàn)分組群聊

一、基礎(chǔ)

1. workerman

workerman是國(guó)人開發(fā)的良心高性能的PHP socket 服務(wù)器框架,在全球最大同性交友平臺(tái)gayHub的star都4K多,可以想象是多么的牛X。

可以單獨(dú)部署,也可以整合進(jìn)MVC的框架(TP,laravel等),可以說(shuō)非常實(shí)用,并發(fā)效果也好。

官網(wǎng)地址:

http://www.workerman.net/workerman

gayhub地址:

https://github.com/walkor/workerman/

2. gateway-worker

gateway-worker(后面直接稱gateway)是基于 workerman開發(fā)的TCP長(zhǎng)連接框架,用于快速開發(fā)TCP長(zhǎng)連接應(yīng)用。

在線聊天一般都是實(shí)用長(zhǎng)連接保持通信,使用 workerman雖然能夠做到同樣的效果,但是gateway更加的方便快捷。

(輪詢構(gòu)建的聊天室已經(jīng)OUT了,實(shí)在是太…)

gayhub地址:

https://github.com/walkor/GatewayWorker

3. gatewayClient

gateClient是用來(lái)輔助 workerman或者是gateway進(jìn)行用戶分組以及向用戶發(fā)送信息的組件,同時(shí),能夠快速便捷的將原有系統(tǒng)的uid和clientid綁定起來(lái)。

gayhub地址:

https://github.com/walkor/GatewayClient

二、理論:

1. 與MVC系統(tǒng)整合的原則:

·現(xiàn)有mvc框架項(xiàng)目與GatewayWorker獨(dú)立部署互不干擾;

·所有的業(yè)務(wù)邏輯都由網(wǎng)站頁(yè)面post/get到mvc框架中完成;

·GatewayWorker不接受客戶端發(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)完成推送。

2. 實(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(用戶id或者客戶端唯一標(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ā)送即可。

三、實(shí)現(xiàn)—配置和開啟Gateway:

1.下載和使用gateway

可以單獨(dú)使用,也可以放在框架的public目錄下。

2.編輯start.php

·start.php是需要使用php命令行運(yùn)行的。

·注意require_once的路徑

ini_set('display_errors',?'on'); use?WorkermanWorker; if(strpos(strtolower(PHP_OS),?'win')?===?0) { ????exit("start.php?not?support?windows,?please?use?start_for_win.batn"); } //?檢查擴(kuò)展 if(!extension_loaded('pcntl')) { ????exit("Please?install?pcntl?extension.See?http://doc3.workerman.net/appendices/install-extension.htmln"); } if(!extension_loaded('posix')) { ????exit("Please?install?posix?extension.See?http://doc3.workerman.net/appendices/install-extension.htmln"); } //?標(biāo)記是全局啟動(dòng) define('GLOBAL_START',?1); //?注意這里的路徑 require_once?'../vendor/autoload.php'; //?加載所有Applications/*/start.php,以便啟動(dòng)所有服務(wù) foreach(glob(__DIR__.'/Applications/*/start*.php')?as?$start_file) { ????require_once?$start_file; } //?運(yùn)行所有服務(wù) Worker::runAll();

3. start_gateway.php

·在ApplicationsYourAppstart_gateway.php中可以編輯

//?部分文件內(nèi)容 //將$gateway改成websocket協(xié)議,demo中是text協(xié)議 $gateway?=?new?Gateway("websocket://0.0.0.0:8282");

4.start_register.php

·需要注意start_register.php 中$register必須是text協(xié)議,同時(shí)需要注意端口

//?register?服務(wù)必須是text協(xié)議 $register?=?new?Register('text://192.168.124.125:1238');

5. 配置好后,開啟start.php

$?php?start.php?start

四、實(shí)現(xiàn)-服務(wù)端開發(fā)

上面提到了,用戶只有在觸發(fā)連接的時(shí)候才經(jīng)過(guò)gateway的onConnect($client_id),而所有的業(yè)務(wù)操作都應(yīng)該在web系統(tǒng)中實(shí)現(xiàn)。

因此我創(chuàng)建了一個(gè)GatewatServer.php的controller,負(fù)責(zé)處理這些業(yè)務(wù)

<?php /**  * Author: root  * Date  : 17-3-27  * time  : 上午12:32  */ namespace appindexcontroller; use GatewayClientGateway; use thinkCache; use thinkController; use thinkRequest; use thinkSession; class GatewayServer extends Controller {     public function _initialize(){     }     public function bind(Request $request)     {         // 用戶連接websocket之后,綁定uid和clientid,同時(shí)進(jìn)行分組,根據(jù)接收到的roomid進(jìn)行分組操作         $userGuid=Session::get(&#39;loginuser&#39;);         $roomId=intval(trimAll($request->post('room'))); ????????$clientId=trimAll($request-&gt;post('client_id')); ????????//?接受到上面的三個(gè)參數(shù),進(jìn)行分組操作 ????????Gateway::$registerAddress?=?'192.168.124.125:1238'; ????????//?client_id與uid綁定 ????????//?Gateway::bindUid($clientId,?$userGuid); ????????//?加入某個(gè)群組(可調(diào)用多次加入多個(gè)群組)?將clientid加入roomid分組中 ????????Gateway::joinGroup($clientId,?$roomId); ????????//?返回ajax?json信息 ????????$dataArr=[ ????????????'code'=&gt;$userGuid, ????????????'status'=&gt;true, ????????????'message'=&gt;'Group?Success' ????????]; ????????return?json()-&gt;data($dataArr); ????} ????//?接受用戶的信息?并且發(fā)送 ????public?function?send(Request?$request){ ????????Gateway::$registerAddress?=?'192.168.124.125:1238'; ????????//?獲得數(shù)據(jù) ????????$userGuid=Session::get('loginuser'); ????????$roomId=intval(trimAll($request-&gt;post('room'))); ????????$message=trim($request-&gt;post('message')); ????????//?獲得用戶的稱呼 ????????$userInfo=Cache::get($userGuid); ????????//?將用戶的昵稱以及用戶的message進(jìn)行拼接 ????????$nickname=$userInfo['nickname']; ????????$message=$nickname."?:?".$message; ????????//?發(fā)送信息應(yīng)當(dāng)發(fā)送json數(shù)據(jù),同時(shí)應(yīng)該返回發(fā)送的用戶的guid,用于客戶端進(jìn)行判斷使用 ????????$dataArr=json_encode(array( ????????????'message'?=&gt;?$message, ????????????'user'=&gt;$userGuid ????????)); ????????//?向roomId的分組發(fā)送數(shù)據(jù) ????????Gateway::sendToGroup($roomId,$dataArr); ????} }

五、實(shí)現(xiàn)-客戶端連接與發(fā)送/接收:

開啟了gateway之后,就可以監(jiān)聽并且等待瀏覽器接入了。

客戶端這里使用js監(jiān)聽websocket:

1. 用于處理客戶端連接websocket以及接收消息

//?這個(gè)示例和gateway官網(wǎng)的示例是一樣的 ????//?監(jiān)聽端口 ????ws?=?new?WebSocket("ws://192.168.124.125:8282"); ????//?綁定分組的ajaxURL ????var?ajaxUrl="{:url('/gateway/bind')}"; ????//?發(fā)送消息的ajaxURL ????var?ajaxMsgUrl="{:url('/gateway/send')}"; ????//?通過(guò)房間號(hào)進(jìn)行分組 ????var?roomId="{$roomInfo.guid}"; ????//?獲取當(dāng)前登錄用戶的guid,用于標(biāo)識(shí)是自己發(fā)送的信息 ????var?loginUser="{$userLoginInfo.guid}"; ????//?獲取當(dāng)前房間號(hào)的主播的uid,用于標(biāo)識(shí)是主播發(fā)送的信息 ????var?roomUser="{$roomInfo.uid}"; ????//?服務(wù)端主動(dòng)推送消息時(shí)會(huì)觸發(fā)這里的onmessage ????ws.onmessage?=?function(e){ ????????//?console.log(e.data); ????????//?json數(shù)據(jù)轉(zhuǎn)換成js對(duì)象 ????????var?data?=?eval("("+e.data+")"); ????????var?type?=?data.type?||?''; ????????switch(type){ ????????????//?Events.php中返回的init類型的消息,將client_id發(fā)給后臺(tái)進(jìn)行uid綁定 ????????????case?'init': ????????????????//?利用jquery發(fā)起ajax請(qǐng)求,將client_id發(fā)給后端進(jìn)行uid綁定 ????????????????$.post(ajaxUrl,?{client_id:?data.client_id,room:roomId},?function(data){ ????????????????????//?console.log(data); ????????????????},?'json'); ????????????????break; ????????????//?當(dāng)mvc框架調(diào)用GatewayClient發(fā)消息時(shí)直接alert出來(lái) ????????????default?: ????????????????//?如果登陸用戶的guid和數(shù)據(jù)發(fā)送者的guid一樣,則使用不同的顏色(只能自己看到) ????????????????if(loginUser?==?data.user){ ????????????????????addMsgToHtml(data.message,'#F37B1D'); ????????????????????break; ????????????????//?如果發(fā)送者的guid和主播uid一樣,則對(duì)所有的顯示都增加一個(gè)[主播標(biāo)識(shí)] ????????????????}else?if(data.user==roomUser){ ????????????????????addMsgToHtml("[主播]?"+data.message,'#0e90d2'); ????????????????????break; ????????????????}else{ ????????????????//?其他的就正常發(fā)送消息 ????????????????????addMsgToHtml(data.message,'#333'); ????????????????} ????????????????break; ????????} ????};

2. 用于將接收到的消息添加到div中進(jìn)行顯示

//?向面板中增加新接收到的消息 ????//?其中message是消息,color是顯示的顏色,主要為了區(qū)分主播以及自己發(fā)送的消息和系統(tǒng)提示 ????function?addMsgToHtml(message,color)?{ ????????if(message.length==0){ ????????????return?false; ????????} ????????//?獲取html,并且增加html ????????var?obj=$("#room-viedo-chat"); ????????var?html=obj.html(); ????????//? ????????html+='<p><font>'+message+'</font></p>'; ????????obj.html(html); ????????//?將滾動(dòng)條滾動(dòng)到底部 ????????obj.scrollTop(obj[0].scrollHeight); ????}

3.用于發(fā)送消息

//?發(fā)送聊天消息 ????function?sendMsg(){ ????????//?去掉onclick屬性,使得3秒之內(nèi)無(wú)法發(fā)送信息 ????????$("#sendMsgBox").attr('onclick',''); ????????var?btnObj=$("#sendMsgBtn"); ????????var?tmpNum=3; ????????var?tmpMsg=tmpNum+'?S'; ????????btnObj.text(tmpMsg); ????????var?int?=setInterval(function?()?{ ????????????//?3秒之內(nèi)不能發(fā)送信息,3秒之后,回復(fù)onclick屬性以及文字 ????????????if(tmpNum==0){ ????????????????tmpMsg="發(fā)送"; ????????????????clearInterval(int); ????????????????btnObj.text("發(fā)送"); ????????????????$("#sendMsgBox").attr('onclick','sendMsg()'); ????????????} ????????????btnObj.text(tmpMsg); ????????????tmpNum-=1; ????????????tmpMsg=tmpNum+'?S'; ????????},1000); ????????var?message=$("#chattext").val().trim(); ????????var?obj=$("#room-viedo-chat"); ????????var?html=obj.html(); ????????if(message.length&gt;=140){ ????????????//?獲取html,并且增加html ????????????addMsgToHtml("系統(tǒng)提示:?不能超過(guò)140個(gè)字符","#8b0000"); ????????????return?false; ????????} ????????if(message.length==0){ ????????????//?獲取html,并且增加html ????????????addMsgToHtml("系統(tǒng)提示:?不能發(fā)送空消息","#8b0000"); ????????????return?false; ????????} ????????//?向server端發(fā)送ajax請(qǐng)求 ????????$.post(ajaxMsgUrl,{room:roomId,message:message},function?(data)?{ ????????},'json'); ????????return?false; ????}

4.一點(diǎn)兒html代碼

<!--chat box start --> ????<div> ????</div> ????<div> ????????<div> ????????????<textarea></textarea> ????????</div> ????????<div> ????????????<span> ????????????????發(fā)送 ????????????</span> ????????</div> ????</div> ????<!--chat box end -->

六、效果:

效果很明顯:

·系統(tǒng)提示是單獨(dú)的顏色

·本人發(fā)布的,是自己能夠分辨的橙色

·主播發(fā)布的是藍(lán)色,同時(shí)前面有[主播]標(biāo)識(shí)

·看其他人發(fā)布的就是普通的顏色

workerman怎么實(shí)現(xiàn)分組群聊

PHP中文網(wǎng),有大量免費(fèi)的workerman入門教程,歡迎大家學(xué)習(xí)!

以上就是

? 版權(quán)聲明
THE END
喜歡就支持一下吧
點(diǎn)贊15 分享