如何用PHP对接Socket.IO?Node.js转PHP及Laravel适配诉求
Hey there! Let's tackle converting your Node.js Socket.IO + RabbitMQ setup to Laravel/PHP. First, a quick heads-up: PHP isn't natively event-driven like Node.js, so we'll need to use an async PHP library that supports the Socket.IO protocol. My go-to here is workerman/php-socket.io—it's a solid implementation that plays nicely with Laravel.
Step 1: Install Dependencies
First, add the required packages to your Laravel project:
composer require workerman/php-socket.io php-amqplib/php-amqplib
workerman/php-socket.io: Implements the Socket.IO server in PHPphp-amqplib/php-amqplib: PHP client for RabbitMQ
Step 2: Create an Artisan Command for the Socket.IO Server
We'll build a custom Artisan command to manage our Socket.IO server (this makes it easy to start/stop the service within Laravel).
Run this to generate the command skeleton:
php artisan make:command SocketIOServer
Replace the generated app/Console/Commands/SocketIOServer.php with this code:
<?php namespace App\Console\Commands; use Illuminate\Console\Command; use Workerman\Worker; use Workerman\SocketIO\SocketIO; use PhpAmqpLib\Connection\AMQPStreamConnection; class SocketIOServer extends Command { protected $signature = 'socket:serve'; protected $description = 'Start Socket.IO server to broadcast RabbitMQ messages to frontend'; public function handle() { // Initialize Socket.IO server on port 2021 (adjust port as needed) $io = new SocketIO(2021); // Track connected clients (optional, useful for debugging) $connectedClients = []; // Handle new client connections $io->on('connection', function ($socket) use (&$connectedClients) { $this->info("New client connected: {$socket->id}"); $connectedClients[$socket->id] = $socket; // Handle client disconnection $socket->on('disconnect', function () use ($socket, &$connectedClients) { $this->info("Client disconnected: {$socket->id}"); unset($connectedClients[$socket->id]); }); }); // Connect to RabbitMQ (match your Node.js credentials) try { $rabbitConnection = new AMQPStreamConnection( 'x.x.x.x', // RabbitMQ host 1234, // RabbitMQ port 'your_username', // RabbitMQ username 'your_password' // RabbitMQ password ); $channel = $rabbitConnection->channel(); // Declare the queue (matches your Node.js queue name '1') $queueName = '1'; $channel->queue_declare($queueName, false, true, false, false); $channel->queue_bind($queueName, '', '#'); // Bind to all routing keys // Consume messages from RabbitMQ $messageCallback = function ($msg) use ($io) { // Parse the message (match your Node.js message structure) $rawMessage = json_decode($msg->body, true); $messageData = $rawMessage['data']['data'] ?? $rawMessage; $this->info("Broadcasting message: " . json_encode($messageData)); // Send message to all connected Socket.IO clients $io->emit('message-name', $messageData); }; $channel->basic_consume($queueName, '', false, true, false, false, $messageCallback); // Run RabbitMQ consumer in a separate worker $rabbitWorker = new Worker(); $rabbitWorker->onWorkerStart = function () use ($channel) { while ($channel->is_consuming()) { $channel->wait(); } }; // Start all workers Worker::runAll(); } catch (\Exception $e) { $this->error("RabbitMQ connection failed: " . $e->getMessage()); } } }
Step 3: Adjust Frontend Code
Update your HTML to connect to the PHP Socket.IO server (note the port change to 2021):
<!DOCTYPE html> <html> <head> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.3.0/socket.io.js"></script> <script> (function () { const onMessage = (data) => { console.log('Received message:', data); }; var connectToServer = function () { // Connect to PHP Socket.IO server var socket = io.connect('http://localhost:2021'); socket.on('message-name', onMessage); // Optional: Add connection status logging socket.on('connect', () => console.log('Connected to PHP Socket.IO server')); socket.on('disconnect', () => console.log('Disconnected from server')); }; connectToServer(); })(); </script> </head> <body> </body> </html>
Step 4: Start the Server
Run the Artisan command to launch your Socket.IO server:
php artisan socket:serve
Key Notes & Fixes from Your Original Node.js Code
- I fixed a bug in your original Node.js code: you had
io.sockets.on('connection')inside the RabbitMQ message callback, which would re-bind the connection event every time a message arrived (causing duplicate events). The PHP version handles client connections once, outside the message consumer. - Ensure the RabbitMQ credentials, host, port, and queue name match exactly what you used in Node.js.
- Make sure port 2021 is open in your firewall and not used by another service.
- If you need to push messages from other parts of your Laravel app (e.g., controllers), you can use Workerman's remote push feature (refer to their official docs for implementation details).
内容的提问来源于stack exchange,提问作者Jaydeep Charadva

