Published: Dec. 13th, 2024
If you've ever wanted to implement real-time communication in your PHP applications, Ratchet is a fantastic library to use. It enables you to create WebSocket servers with ease, allowing bi-directional communication between the server and clients. In this post, I'll walk you through a simple WebSocket server implementation using Ratchet.
Here's the code we'll be working with:
require '../vendor/autoload.php'
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
use Ratchet\Server\IoServer;
class Websocket_Server extends MessageComponentInterface {
protected $connections;
public function __construct () {
$this->connections = [];
echo "Websocket Server Started.\n";
}
public function onOpen (ConnectionInterface $conn) {
$this->connections[$conn->resourceId] = [];
echo "New Connection: ".$conn->resourceId;
}
public function onMessage (ConnectionInterface $from, $msg) {
echo "New message from: ".$from->resourceId;
if($msg === 'FOO') {
$from->send('USER SENT FOO TO THE SERVER.');
} else {
$from->send('SOMETHING UNKNOWN WAS SENT TO THE SERVER.');
}
}
public function onClose (ConnectionInterface $conn) {
unset($this->connections[$conn->resourceId]);
echo "Disconnected: ".$from->resourceId;
}
public function onError (ConnectionInterface $conn, \Exception $e) {
echo "Error: ".$e->getMessage();
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(
new WsServer(
new Websocket_Server()
)
),
3000
);
The vendor/autoload.php file is required to load Ratchet and other dependencies installed via Composer. Key namespaces are imported, including Ratchet\MessageComponentInterface for the server logic and Ratchet\ConnectionInterface for handling client connections.
The Websocket_Server class implements the MessageComponentInterface. This interface requires four core methods:
onOpen: Handles a new client connection.
onMessage: Processes messages sent from a client.
onClose: Cleans up after a client disconnects.
onError: Handles exceptions or errors.
The class uses an array, $connections, to manage active client connections.
__construct: Initializes the $connections array and outputs a message indicating that the server has started.
public function __construct () {
$this->connections = [];
echo "Websocket Server Started.\n";
}
onOpen: Called when a new client connects. Each client is assigned a unique resourceId (a numeric identifier). This ID is stored in the $connections array, and a message is logged to the console.
public function onOpen (ConnectionInterface $conn) {
$this->connections[$conn->resourceId] = [];
echo "New Connection: ".$conn->resourceId;
}
onMessage: This method is triggered whenever a client sends a message. It logs the message sender's ID and provides simple conditional logic: If the client sends "FOO", the server responds with a predefined message. Otherwise, it sends a generic response for unknown messages.
public function onMessage (ConnectionInterface $from, $msg) {
echo "New message from: ".$from->resourceId;
if($msg === 'FOO') {
$from->send('USER SENT FOO TO THE SERVER.');
} else {
$from->send('SOMETHING UNKNOWN WAS SENT TO THE SERVER.');
}
}
onClose: Called when a client disconnects. The client is removed from the $connections array, and a message is logged.
public function onClose (ConnectionInterface $conn) {
unset($this->connections[$conn->resourceId]);
echo "Disconnected: ".$from->resourceId;
}
onError: Logs the error message and closes the connection in case of an exception.
public function onError (ConnectionInterface $conn, \Exception $e) {
echo "Error: ".$e->getMessage();
$conn->close();
}
The server is instantiated using the IoServer::factory() method. The server stack includes: HttpServer: Wraps the WebSocket server for HTTP communication. WsServer: Wraps our Websocket_Server class for WebSocket protocol handling.
The server listens on port 3000. You can start the server by running the script in your terminal:
php websocket_server.php
Use a browser-based clients to connect to the server (ws://localhost:3000) and test sending/receiving messages.