本次僅記錄 webSocket 與 Swoole 配合打造一個(gè)小型的聊天室,功能簡陋,但是可以作為一個(gè)很好的入門案例。
本來就是作為一個(gè)很小的案例來寫的,包含的功能點(diǎn)也不是那多,索性就按照最最最低配置來搞。
能夠顯示聊天消息的聊天區(qū),同時(shí)兼顧顯示鏈接狀態(tài),當(dāng)前是否連接成功,或者服務(wù)端是否斷開連接,而前端不知道的狀況。
一個(gè)輸入框,純粹的輸入框 ?
點(diǎn)擊按鈕發(fā)送不刷新頁面,同時(shí)清空當(dāng)前輸入框內(nèi)容,就簡單的一個(gè) button 而已,點(diǎn)擊執(zhí)行,不支持回車發(fā)送。
收到消息,滾動(dòng)條自動(dòng)觸底,這個(gè)功能在某些使用場景是方便的,但又會(huì)造成某些場景使用不方便,方便在于有新消息不需要人工滾動(dòng),不方便在于,可能你在看歷史消息,它自動(dòng)觸底了…還需要根據(jù)自己實(shí)際需求優(yōu)化一下下。
隨機(jī)昵稱,當(dāng)然不需要保存,刷新即丟,在收到消息如果是自己發(fā)送的,則顯示 [ 我 ] 在某某時(shí)候發(fā)送了某某消息,而不是顯示昵稱字符串。
直接粘貼復(fù)制的
composer create-project topthink/think tpcd tpcomposer require topthink/think-swoole
因?yàn)槭菧y試項(xiàng)目,所有的都是默認(rèn)安裝,在安裝完之后,訪問前端頁面,使用 view 方法會(huì)報(bào)錯(cuò),百度一下就有解決方案了。
參考文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/WebSocket
前端頁面代碼:
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>打工人聊天室</title> <!--需要引入jq 文件--></head><style> .content { height: 400px; max-width: 400px; overflow: auto; border-radius: 5px; border: 1px solid #f0f0f0; }</style><body> <div id="content" class="content"> <p>聊天區(qū)域</p> </div> 你好打工人:<samp id="nickname">昵稱</samp> <br> 本次連接FD: <samp id="fd-samp"></samp> <br> <input type="text" id="msg"> <input type="hidden" id="fd" value=""> <button id="send" onclick="send()">發(fā)送</button></body></html>
JS 代碼:
在服務(wù)器信息回執(zhí)時(shí),會(huì)有第一次連接回執(zhí),還是服務(wù)端發(fā)送消息回執(zhí)的狀態(tài)區(qū)別,通過 msgType 來分辨,如果是第一次連接的回執(zhí)消息,則把 FD 做一個(gè)頁面留存,并不顯示在聊天消息區(qū),如果收到的是消息回執(zhí),就直接顯示到聊天消息區(qū)。
還有就是,前后端相互通信發(fā)送的東西,都是字符串性質(zhì)最優(yōu),我前端處理的方法是先組合成一個(gè)對(duì)象,然后轉(zhuǎn) JSON 串。
<script> //滾動(dòng)條最底部 function scrolltest() { var div = document.getElementById("content"); div.scrollTop = div.scrollHeight; } var wsServer = 'ws://127.0.0.1:9502'; var websocket = new WebSocket(wsServer); var nickname = Math.random().toString(36).substr(2); thisFd = ''; $('#nickname').html(nickname); //點(diǎn)擊發(fā)送 function send() { var msg = $('#msg').val(); var data = { 'nickname': nickname, 'fd': thisFd, 'data': msg } //生成json 方便后臺(tái)接收以及使用 var data = JSON.stringify(data); websocket.send(data); //然后清空 $('#msg').val(''); } //鏈接成功 websocket.onopen = function (evt) { $("#content >p:last-child").after('<p> 服務(wù)器已連接,開始聊天吧 </p>'); }; //鏈接斷開 websocket.onclose = function (evt) { $("#content >p:last-child").after('<p> 服務(wù)器已斷開,請(qǐng)重新連接 </p>'); }; //收到服務(wù)器消息 websocket.onmessage = function (evt) { //握手成功后,會(huì)接受到服務(wù)端返回的fd ,msgType = 1 //字符串格式化成json var data = eval('(' + evt.data + ')'); // console.log(evt.data); switch (data.msgType) { case 1: thisFd = data.fd; $('#fd-samp').html(thisFd); $('#fd').val(thisFd); break; case 2: if (data.nickname == nickname) { data.nickname = '我'; } $("#content >p:last-child").after('<p>' + data.nickname + ' 在 ' + data.time + ' 說:<br>' + data.data + '</p>'); //接收到消息自動(dòng)觸底 scrolltest(); break; } }; //服務(wù)器異常 websocket.onerror = function (evt, e) { $("#content >p:last-child").after('<p> 服務(wù)器異常 </p>'); };</script>
服務(wù)端代碼
服務(wù)端需要 callback 前端過來的消息,轉(zhuǎn)成對(duì)象數(shù)據(jù),然后增加點(diǎn)自定義數(shù)據(jù)直接原樣返回,并且群發(fā)到前端。
<?php //創(chuàng)建WebSocket Server對(duì)象,監(jiān)聽0.0.0.0:9502端口 $ws = new Swoole\WebSocket\Server('0.0.0.0', 9502); //監(jiān)聽WebSocket連接打開事件 $ws->on('open', function ($ws, $request){ $fd = $request->fd; $data = json_encode([ 'fd' => $request->fd, 'msgType' => 1 //代表第一次連接,前端處理fd ]); $ws->push($request->fd, $data); }); //監(jiān)聽WebSocket消息事件 $ws->on('message', function ($ws, $frame) { $stats = $ws->stats(); //格式化接收到j(luò)son $data = json_decode($frame->data); // 原基礎(chǔ)上不動(dòng),增加一些自定義 $data->msgType = 2; //代表服務(wù)器端回復(fù) $data->time = date('Y-m-d H-i-s'); $data = json_encode($data); //因?yàn)槭橇奶焓遥园ㄗ约憾夹枰盏交貓?zhí),就直接群發(fā) swoole 提供 connections 方法 包含了所有在線的 fd foreach ($ws->connections as $conn_fd){ $ws->push($conn_fd,$data); } }); //監(jiān)聽WebSocket連接關(guān)閉事件 $ws->on('close', function ($ws, $fd) {// echo "client-{$fd} is closed\n"; }); $ws->start();
代碼齊全之后,接下來就只需要在控制臺(tái)執(zhí)行以下 PHP 文件就行。
然后前臺(tái)直接訪問你的網(wǎng)站地址,我的是本地 127.0.0.1
多開幾個(gè)窗口模擬多個(gè)用戶,然后發(fā)送消息測試即可:
你好,打工人。
代碼很簡單,難度不大,但是可以很簡潔的反應(yīng)出 webScoket 和 Swoole 的一種強(qiáng)大。
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com