利用webSocket與Swoole打造一個小型聊天室

前言

????本次僅記錄 websocket 與 swoole 配合打造一個小型的聊天室,功能簡陋,但是可以作為一個很好的入門案例。

項目簡介

????本來就是作為一個很小的案例來寫的,包含的功能點也不是那多,索性就按照最最最低配置來搞。

  • 能夠顯示聊天消息的聊天區(qū),同時兼顧顯示鏈接狀態(tài),當(dāng)前是否連接成功,或者服務(wù)端是否斷開連接,而前端不知道的狀況。

  • 一個輸入框,純粹的輸入框 ?

  • 點擊按鈕發(fā)送不刷新頁面,同時清空當(dāng)前輸入框內(nèi)容,就簡單的一個 button 而已,點擊執(zhí)行,不支持回車發(fā)送。

  • 收到消息,滾動條自動觸底,這個功能在某些使用場景是方便的,但又會造成某些場景使用不方便,方便在于有新消息不需要人工滾動,不方便在于,可能你在看歷史消息,它自動觸底了…還需要根據(jù)自己實際需求優(yōu)化一下下。

  • 隨機昵稱,當(dāng)然不需要保存,刷新即丟,在收到消息如果是自己發(fā)送的,則顯示 [ 我 ] 在某某時候發(fā)送了某某消息,而不是顯示昵稱字符串。

項目環(huán)境

直接粘貼復(fù)制的

composer?create-project?topthink/think?tpcd?tpcomposer?require?topthink/think-swoole

????因為是測試項目,所有的都是默認安裝,在安裝完之后,訪問前端頁面,使用 view 方法會報錯,百度一下就有解決方案了。

webSocket 的使用

參考文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket

  1. onopen() 發(fā)起連接,連接成功后執(zhí)行。
  2. onclose() 連接斷開后執(zhí)行。
  3. onmessage() 收到服務(wù)端消息后執(zhí)行。
  4. onerror() 服務(wù)器異常執(zhí)行。
    其實,webSocket 就這些常用方法,也沒啥特殊要求的,他就是作為一個保持連接,接收服務(wù)器狀態(tài)的一個瀏覽器的 API 存在,非常簡潔方便。

前端頁面代碼:

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>聊天區(qū)域</p>????????????</div>????????????你好打工人:<samp>昵稱</samp>?<br>????????????本次連接FD:?<samp></samp>?<br>????????????<input>????????????<input>????????????<button>發(fā)送</button>

JS 代碼:

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

????還有就是,前后端相互通信發(fā)送的東西,都是字符串性質(zhì)最優(yōu),我前端處理的方法是先組合成一個對象,然后轉(zhuǎn) JSON 串。

<script>    //滾動條最底部    function scrolltest() {        var div = document.getElementById("content");        div.scrollTop = div.scrollHeight;    }    var wsServer = &#39;ws://127.0.0.1:9502&#39;;    var websocket = new WebSocket(wsServer);    var nickname = Math.random().toString(36).substr(2);    thisFd = &#39;&#39;;    $(&#39;#nickname&#39;).html(nickname);    //點擊發(fā)送    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) {        $("#content >p:last-child").after(&#39;<p> 服務(wù)器已連接,開始聊天吧 &#39;);    };    //鏈接斷開    websocket.onclose = function (evt) {        $("#content >p:last-child").after(&#39;<p> 服務(wù)器已斷開,請重新連接 &#39;);    };    //收到服務(wù)器消息    websocket.onmessage = function (evt) {        //握手成功后,會接受到服務(wù)端返回的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;        }    };    //服務(wù)器異常    websocket.onerror = function (evt, e) {        $("#content >p:last-child").after(&#39;<p> 服務(wù)器異常 &#39;);    };</script>

服務(wù)端代碼
????服務(wù)端需要 callback 前端過來的消息,轉(zhuǎn)成對象數(shù)據(jù),然后增加點自定義數(shù)據(jù)直接原樣返回,并且群發(fā)到前端。

<?php     //創(chuàng)建WebSocket Server對象,監(jiān)聽0.0.0.0:9502端口    $ws = new SwooleWebSocketServer(&#39;0.0.0.0&#39;, 9502);    //監(jiān)聽WebSocket連接打開事件    $ws->on('open',?function?($ws,?$request){????????$fd?=?$request-&gt;fd;????????$data?=?json_encode([????????????'fd'?=&gt;?$request-&gt;fd,????????????'msgType'?=&gt;?1??//代表第一次連接,前端處理fd????????]);????????$ws-&gt;push($request-&gt;fd,?$data);????});????//監(jiān)聽WebSocket消息事件????$ws-&gt;on('message',?function?($ws,?$frame)?{????????$stats?=?$ws-&gt;stats();????????//格式化接收到j(luò)son????????$data?=?json_decode($frame-&gt;data);????????//?原基礎(chǔ)上不動,增加一些自定義????????$data-&gt;msgType?=?2;?//代表服務(wù)器端回復(fù)????????$data-&gt;time?=?date('Y-m-d?H-i-s');????????$data?=?json_encode($data);????????//因為是聊天室,所以包括自己都需要收到回執(zhí),就直接群發(fā)?swoole?提供?connections?方法?包含了所有在線的?fd????????foreach?($ws-&gt;connections?as?$conn_fd){????????????$ws-&gt;push($conn_fd,$data);????????}????});????//監(jiān)聽WebSocket連接關(guān)閉事件????$ws-&gt;on('close',?function?($ws,?$fd)?{//????????echo?"client-{$fd}?is?closedn";????});????$ws-&gt;start();

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

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

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

你好,打工人。

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

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