在現代的Web開發過程中,實時性需要成為我們日常處理的問題之一。對于此類需求,我們通常會使用一些主流的協議,比如Long Polling,SSE(Server-Sent Events),或者Websocket。其中Websocket是一種基于TCP協議實現的雙向通信的協議,在近些年得到了廣泛的使用。 他的好處顯而易見,無論是在游戲、聊天、視頻會議等實時交互性應用中,都有著卓越的性能和優秀的用戶體驗。
由于PHP是一個在Web開發中得到廣泛應用的動態解釋型語言,因此本篇文章主要探討基于PHP的Websocket服務端如何快速實現。以Swoole為例,Swoole是PHP的擴展,為開發者提供了內置的Websocket支持,使得我們可以方便地快速搭建Websocket服務端,做到快速優雅的處理客戶端的連接、斷開、發送消息等。
首先,我們需要了解如何開始Swoole的Websocket服務器,其主要代碼如下:
//開啟Websocket服務 $server = new swoole_websocket_server("0.0.0.0", 9502); //監聽WebSocket連接打開事件 $server->on('open', function (swoole_websocket_server $server, swoole_http_request $request) { echo "server: handshake success with fd{$request->fd}\n"; }); //監聽WebSocket消息事件 $server->on('message', function (swoole_websocket_server $server, swoole_websocket_frame $frame) { echo "receive from {$frame->fd}: {$frame->data},opcode: {$frame->opcode},fin: {$frame->finish}\n"; $server->push($frame->fd, "this is server"); }); //監聽WebSocket連接關閉事件 $server->on('close', function (swoole_websocket_server $server, $fd) { echo "client {$fd} closed\n"; }); //啟動服務器 $server->start();
上述代碼為搭建一個基本的Websocket服務端所需的全部代碼,非常少量且輕便。接下來簡單介紹每個事件的主要作用:
1. 'open'事件:WebSocket握手成功后觸發的事件,通過$request可以獲取客戶端傳遞的一些參數,比如HTTP協議頭
2. 'message'事件:當服務端接收到客戶端發送過來的數據時觸發,在本示例中,我們將接收到的消息原封不動的通過push方法返回給客戶端
3. 'close'事件:當服務端和客戶端的連接斷開時觸發,可以通過$fd參數獲取到斷開連接的客戶端ID
接下來,我們來嘗試一下使用JS生成一個Simple的Websocket客戶端:
function websocketClient(url) { //建立連接 this.ws = new WebSocket(url); //連接成功回調函數 this.ws.onopen = function () { console.log("連接成功!"); }; //接收消息回調函數 this.ws.onmessage = function (e) { console.log("接收到服務端的消息了:" + e.data); }; //關閉連接回調函數 this.ws.onclose = function () { console.log("連接關閉!"); }; //錯誤回調函數 this.ws.onerror = function () { console.log("連接錯誤!"); } //發送消息函數 this.send = function (message) { this.ws.send(JSON.stringify(message)); } //斷開連接函數 this.close = function () { this.ws.close(); } }
與服務端不同的是,在與客戶端的建立連接時,我們會發起一個WebSocket的握手請求,通過監聽onopen事件,在連接建立后做一些處理,如打印一些日志信息。而與服務器通信時,我們則主要監聽onmessage事件來接受服務端的消息。在啟動客戶端后,我們就可以通過簡單的send()方法來發送消息,通過close()方法來斷開連接。
Websocket提供了多種類型的消息,包括Opcode,FIN等。不同類型的消息具體含義可以參考Websocket協議文檔。不過大多數情況下,默認Opcode=1,fin=1。前者表示文本消息,而后者表示消息結束后需要關閉此次連接。具體代碼如下:
$server->push($frame->fd, "this is server");
當然,在實際的開發過程中,我們還需要考慮到安全風險、錯誤處理等諸多問題。并且,我們可能也會考慮到一些更高級別的應用需求,例如支持多種協議、集群等。但在本篇文章,我們僅是為了闡述如何快速構建一個快速的Websocket服務端,并且借助一份簡單的JavaScript代碼搭建起它的客戶端。在生產環境中,您可以根據您的實際情況進行針對性的優化和調整。