PHP Ratchet 是一種基于 PHP 語言的 WebSocket 庫,使用 ReactPHP 作為其基礎,能夠快速開發實時應用程序。Ratchet 的出現填補了 PHP 實時通信的空白,使得開發者可以快速構建基于 WebSocket 的實時應用。
下面我們來舉幾個例子來說明 Ratchet 如何運行。
首先,讓我們來看一個簡單的聊天室。客戶端向 WebSocket 服務器發送消息,服務器轉發消息給相應的客戶端。以下是服務器代碼:
可以看出,這里實現了
這部分代碼比較簡單,首先打開 WebSocket 連接,然后分別監聽連接建立和接收消息的事件,在接收到消息后把它顯示在聊天框里。
下面是一個更加實用的例子,一款類似于在線畫圖板的應用。用戶可以在畫布上進行繪畫,其他用戶可以同時觀看繪畫的過程和結果。以下是服務器端代碼:
同樣,這里實現了
這份代碼中,我們使用 canvas 元素實現畫圖功能。在鼠標按下、移動、松開的時候,把相應的事件信息打包成 JSON 格式,并通過 WebSocket 發送給服務器端。在收到服務器端的消息后,根據事件類型進行畫圖操作。
以上兩個例子展示了 Ratchet 的基本用法,這里留給讀者自行探索更多的運用方式。需要注意的是,由于 Ratchet 是基于 WebSockets 實現的,所以應用程序需要在支持 WebSocket 的瀏覽器或移動端客戶端上運行。
下面我們來舉幾個例子來說明 Ratchet 如何運行。
首先,讓我們來看一個簡單的聊天室。客戶端向 WebSocket 服務器發送消息,服務器轉發消息給相應的客戶端。以下是服務器代碼:
<?php use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; <br> class Chat implements MessageComponentInterface { protected $clients; <br> public function __construct() { $this->clients = new \SplObjectStorage; } <br> public function onOpen(ConnectionInterface $conn) { $this->clients->attach($conn); echo "New client joined: {$conn->resourceId}\n"; } <br> public function onMessage(ConnectionInterface $from, $msg) { foreach ($this->clients as $client) { if ($from !== $client) { $client->send($msg); } } } <br> public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); echo "Client {$conn->resourceId} has disconnected\n"; } <br> public function onError(ConnectionInterface $conn, \Exception $e) { echo "An error has occurred: {$e->getMessage()}\n"; $conn->close(); } }
可以看出,這里實現了
MessageComponentInterface
接口,對于該接口定義的 4 個回調函數,分別對應 WebSocket 連接建立、接收消息、斷開連接、異常處理。在onOpen
函數中,把連接添加到$clients
對象的儲存;在onMessage
函數中,循環遍歷$clients
對象,發送消息到相應的客戶端;在onClose
函數中,從$clients
對象中移除連接;在onError
函數中,打印異常信息,并關閉連接。接下來是客戶端代碼:<!DOCTYPE html> <html> <head> <title>Chat Room</title> </head> <body> <div id="chat_box"></div> <hr> <input type="text" id="chat_msg" placeholder="Enter your message..."> <button onclick="sendMessage()">Send</button> <br> <script> var conn = new WebSocket('ws://localhost:8080'); var chatBox = document.getElementById('chat_box'); var chatMsg = document.getElementById('chat_msg'); <br> conn.onopen = function(e) { chatBox.innerHTML += 'Connected to server\n'; }; <br> conn.onmessage = function(e) { chatBox.innerHTML += e.data + '\n'; }; <br> function sendMessage() { var msg = chatMsg.value; conn.send(msg); chatMsg.value = ''; } </script> </body> </html>
這部分代碼比較簡單,首先打開 WebSocket 連接,然后分別監聽連接建立和接收消息的事件,在接收到消息后把它顯示在聊天框里。
下面是一個更加實用的例子,一款類似于在線畫圖板的應用。用戶可以在畫布上進行繪畫,其他用戶可以同時觀看繪畫的過程和結果。以下是服務器端代碼:
<?php use Ratchet\MessageComponentInterface; use Ratchet\ConnectionInterface; <br> class Paint implements MessageComponentInterface { protected $clients; <br> public function __construct() { $this->clients = new \SplObjectStorage; } <br> public function onOpen(ConnectionInterface $conn) { $this->clients->attach($conn); echo "New client joined: {$conn->resourceId}\n"; } <br> public function onMessage(ConnectionInterface $from, $msg) { foreach ($this->clients as $client) { if ($from === $client) { continue; } $client->send($msg); } } <br> public function onClose(ConnectionInterface $conn) { $this->clients->detach($conn); echo "Client {$conn->resourceId} has disconnected\n"; } <br> public function onError(ConnectionInterface $conn, \Exception $e) { echo "An error has occurred: {$e->getMessage()}\n"; $conn->close(); } }
同樣,這里實現了
MessageComponentInterface
接口。和聊天室不同的是,繪畫應用需要監聽鼠標移動和釋放事件,把繪圖數據打包成 JSON 格式發送給所有客戶端。以下是客戶端代碼:<!DOCTYPE html> <html> <head> <title>Paint</title> <style> #canvas { border: 1px solid #ccc; background-color: #fff; } </style> </head> <body> <canvas id="canvas" width="800" height="600"></canvas> <br> <script> var conn = new WebSocket('ws://localhost:8080'); var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var isDrawing = false; <br> function getMousePos(canvas, e) { var rect = canvas.getBoundingClientRect(); return { x: e.clientX - rect.left, y: e.clientY - rect.top }; } <br> canvas.addEventListener('mousedown', function(e) { isDrawing = true; var pos = getMousePos(canvas, e); var data = {event: 'mousedown', x: pos.x, y: pos.y}; conn.send(JSON.stringify(data)); }); <br> canvas.addEventListener('mousemove', function(e) { if (!isDrawing) { return; } var pos = getMousePos(canvas, e); var data = {event: 'mousemove', x: pos.x, y: pos.y}; conn.send(JSON.stringify(data)); }); <br> canvas.addEventListener('mouseup', function(e) { isDrawing = false; var data = {event: 'mouseup'}; conn.send(JSON.stringify(data)); }); <br> conn.onmessage = function(e) { var data = JSON.parse(e.data); switch (data.event) { case 'mousedown': ctx.beginPath(); ctx.moveTo(data.x, data.y); break; case 'mousemove': ctx.lineTo(data.x, data.y); ctx.stroke(); break; case 'mouseup': ctx.closePath(); break; } }; </script> </body> </html>
這份代碼中,我們使用 canvas 元素實現畫圖功能。在鼠標按下、移動、松開的時候,把相應的事件信息打包成 JSON 格式,并通過 WebSocket 發送給服務器端。在收到服務器端的消息后,根據事件類型進行畫圖操作。
以上兩個例子展示了 Ratchet 的基本用法,這里留給讀者自行探索更多的運用方式。需要注意的是,由于 Ratchet 是基于 WebSockets 實現的,所以應用程序需要在支持 WebSocket 的瀏覽器或移動端客戶端上運行。