利用 webSocket 與 Swoole 打造一個小型聊天室(協程)

前言

????前面有寫一個異步簡單的聊天室,然后想著,就把協程的也弄了吧所以就有了這個文章,其實所有的功能都大差不差,就僅僅幾個地方不一樣而已,也都是簡單的地方。
博文地址:利用 websocket 與 swoole 打造一個小型聊天室 (異步)
本次也沒增加功能,就是增加了一個心跳,從前端定時發送一個 ping ,服務端不作反應,僅此而已。

前端頁面代碼:

nbsp;html&gt;  ???? <meta>???? <title>打工人聊天室</title>??? <!--需要引入jq 文件--><style>     .content {         height: 400px;         max-width: 400px;         overflow: auto;         border-radius: 5px;         border: 1px solid #f0f0f0;     }</style>???????????? <div>???????????????? <p>聊天區域</p>???????????? </div>???????????? 你好打工人:<samp>昵稱</samp>?<br>???????????? 本次連接FD:?<samp></samp>?<br>???????????? <input>???????????? <input>???????????? <button>發送</button>  

JS 代碼:

????在服務器信息回執時,會有第一次連接回執,還是服務端發送消息回執的狀態區別,通過 msgType 來分辨,如果是第一次連接的回執消息,則把 FD 做一個頁面留存,并不顯示在聊天消息區,如果收到的是消息回執,就直接顯示到聊天消息區。

????還有就是,前后端相互通信發送的東西,都是字符串性質最優,我前端處理的方法是先組合成一個對象,然后轉 JSON 串。

<script>     //滾動條最底部     function scrolltest() {         var div = document.getElementById("content");         div.scrollTop = div.scrollHeight;    }     var wsServer = &#39;ws://127.0.0.1:9502/websocket&#39;;     var websocket = new WebSocket(wsServer);     var nickname = Math.random().toString(36).substr(2);     thisFd = &#39;&#39;;    $(&#39;#nickname&#39;).html(nickname);     //點擊發送     function send() {         var msg = $(&#39;#msg&#39;).val();         var data = {             &#39;nickname&#39;: nickname,             &#39;fd&#39;: thisFd,             &#39;data&#39;: msg        }         //生成json 方便后臺接收以及使用         var data = JSON.stringify(data);         websocket.send(data);         //然后清空         $(&#39;#msg&#39;).val(&#39;&#39;);    }     //鏈接成功     websocket.onopen = function (evt) {         var data = {             &#39;msgType&#39;: &#39;open&#39;        }         var data = JSON.stringify(data);         $("#content >p:last-child").after(&#39;<p> 服務器已連接,開始聊天吧 &#39;);         websocket.send(data);    };     //鏈接斷開     websocket.onclose = function (evt) {         $("#content >p:last-child").after(&#39;<p> 服務器已斷開,請重新連接 &#39;);    };     //收到服務器消息     websocket.onmessage = function (evt) {         //握手成功后,會接受到服務端返回的fd ,msgType = 1         //字符串格式化成json         var data = eval(&#39;(&#39; + evt.data + &#39;)&#39;);         // console.log(evt.data);         switch (data.msgType) {             case 1:                 thisFd = data.fd;                 $(&#39;#fd-samp&#39;).html(thisFd);                 $(&#39;#fd&#39;).val(thisFd);                 break;            case 2:                 if (data.nickname == nickname) {                     data.nickname = &#39;我&#39;;                }                 $("#content >p:last-child").after(&#39;<p>&#39; + data.nickname + &#39; 在 &#39; + data.time + &#39; 說:<br>&#39; + data.data + &#39;&#39;);                 //接收到消息自動觸底                 scrolltest();                 break;        }    };     //服務器異常     websocket.onerror = function (evt, e) {         $("#content >p:last-child").after(&#39;<p> 服務器異常 &#39;);    };     //心跳,本次新增     function heartbeat() {        var data = {             &#39;msgType&#39;: &#39;ping&#39;,        }         //生成json 方便后臺接收以及使用         var data = JSON.stringify(data);         websocket.send(data);    }     //30 秒一次     setInterval(heartbeat, 30000);</script>

服務端代碼
協程,都需要在 Corun(function () {}) 里。

<?php      //定義獲取當前的id函數     function getObjectId(swooleHttpResponse $response) {         if (PHP_VERSION_ID < 70200) {             $id = spl_object_hash($response);         } else {             $id = spl_object_id($response);        }         return $id;    }     Corun(function () {         $server = new CoHttpServer(&#39;127.0.0.1&#39;, 9502, false);         $server->set([???????????? 'heartbeat_idle_time'??????=&gt;?600,? //?表示一個連接如果600秒內未向服務器發送任何數據,此連接將被強制關閉???????????? 'heartbeat_check_interval'?=&gt;?60,?? //?表示每60秒遍歷一次???????? ]);???????? $server-&gt;handle('/websocket',?function?($request,?$ws)?{???????????? $ws-&gt;upgrade();???????????? global?$wsObjects;???????????? $objectId?=?getObjectId($ws);???????????? $wsObjects[$objectId]?=?$ws;???????????? while?(true)?{???????????????? $frame?=?$ws-&gt;recv();???????????????? if?($frame?===?'')?{???????????????????? unset($wsObjects[$objectId]);???????????????????? $ws-&gt;close();???????????????????? break;???????????????? }?else?if?($frame?===?false)?{???????????????????? echo?'error?:?'?.?swoole_last_error()?.?"n";???????????????????? break;????????????????}? else?{???????????????????? if?($frame-&gt;data?==?'close'?||?get_class($frame)?===?SwooleWebSocketCloseFrame::class)? {???????????????????????? unset($wsObjects[$objectId]);???????????????????????? $ws-&gt;close();???????????????????????? return;???????????????????? }???????????????????? //格式化接收到json???????????????????? $data?=?json_decode($frame-&gt;data);???????????????????? switch?($data-&gt;msgType){???????????????????????? case?'open':???????????????????????????? //鏈接第一次???????????????????????????? $data?=?json_encode([???????????????????????????????? 'fd'?=&gt;?$objectId,???????????????????????????????? 'msgType'?=&gt;?1?? //代表第一次連接,前端處理fd???????????????????????????? ]);???????????????????????????? $ws-&gt;push($data);???????????????????????????? break;???????????????????????? case?'ping':???????????????????????????? //接收到心跳?不作回復 //???????????????????????????? echo??$data-&gt;msgType;???????????????????????????? break;???????????????????????? default?:???????????????????????????? //?原基礎上不動,增加一些自定義???????????????????????????? $data-&gt;msgType?=?2;? //代表服務器端回復???????????????????????????? $data-&gt;time?=?date('Y-m-d?H-i-s');???????????????????????????? $data?=?json_encode($data);???????????????????????????? foreach?($wsObjects?as?$obj)?{???????????????????????????????? $obj-&gt;push($data);???????????????????????????? }???????????????????? }???????????????? }????????????}???????? });???????? $server-&gt;start();???? });

代碼齊全之后,接下來就只需要在控制臺執行以下 PHP 文件就行。
利用 webSocket 與 Swoole 打造一個小型聊天室(協程)

然后前臺直接訪問你的網站地址,我的是本地 127.0.0.1
利用 webSocket 與 Swoole 打造一個小型聊天室(協程)

多開幾個窗口模擬多個用戶,然后發送消息測試即可:
利用 webSocket 與 Swoole 打造一個小型聊天室(協程)

你好,打工人。

代碼很簡單,難度不大,但是可以很簡潔的反應出 webScoket 和 Swoole 的一種強大。

? 版權聲明
THE END
喜歡就支持一下吧
點贊7 分享