php实现websocket
PHP 实现 WebSocket
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议。PHP 可以通过多种方式实现 WebSocket 功能,以下是几种常见的方法:
使用 Ratchet 库
Ratchet 是一个流行的 PHP WebSocket 库,基于 ReactPHP 实现。安装 Ratchet 可以通过 Composer:
composer require cboden/ratchet
创建一个简单的 WebSocket 服务器:
use Ratchet\MessageComponentInterface;
use Ratchet\ConnectionInterface;
use Ratchet\Server\IoServer;
use Ratchet\Http\HttpServer;
use Ratchet\WebSocket\WsServer;
class MyWebSocket implements MessageComponentInterface {
public function onOpen(ConnectionInterface $conn) {
echo "New connection: {$conn->resourceId}\n";
}
public function onMessage(ConnectionInterface $from, $msg) {
echo "Received message: {$msg}\n";
$from->send("Echo: {$msg}");
}
public function onClose(ConnectionInterface $conn) {
echo "Connection closed: {$conn->resourceId}\n";
}
public function onError(ConnectionInterface $conn, \Exception $e) {
echo "Error: {$e->getMessage()}\n";
$conn->close();
}
}
$server = IoServer::factory(
new HttpServer(new WsServer(new MyWebSocket())),
8080
);
$server->run();
运行服务器后,可以通过 JavaScript 客户端连接到 ws://localhost:8080。
使用 Swoole 扩展
Swoole 是一个高性能的 PHP 协程框架,内置 WebSocket 支持。安装 Swoole:
pecl install swoole
创建一个简单的 WebSocket 服务器:
$server = new Swoole\WebSocket\Server("0.0.0.0", 9501);
$server->on('open', function (Swoole\WebSocket\Server $server, $request) {
echo "Connection open: {$request->fd}\n";
});
$server->on('message', function (Swoole\WebSocket\Server $server, $frame) {
echo "Received message: {$frame->data}\n";
$server->push($frame->fd, "Echo: {$frame->data}");
});
$server->on('close', function ($server, $fd) {
echo "Connection closed: {$fd}\n";
});
$server->start();
运行服务器后,可以通过 JavaScript 客户端连接到 ws://localhost:9501。
使用原生 PHP 和 Socket 函数
对于更底层的实现,可以使用 PHP 的 Socket 函数。以下是一个简单的示例:
$host = '0.0.0.0';
$port = 8080;
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
socket_bind($socket, $host, $port);
socket_listen($socket);
while (true) {
$client = socket_accept($socket);
$request = socket_read($client, 1024);
if (preg_match('/Sec-WebSocket-Key: (.*)\r\n/', $request, $match)) {
$key = base64_encode(sha1($match[1] . '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', true));
$headers = "HTTP/1.1 101 Switching Protocols\r\n";
$headers .= "Upgrade: websocket\r\n";
$headers .= "Connection: Upgrade\r\n";
$headers .= "Sec-WebSocket-Accept: $key\r\n\r\n";
socket_write($client, $headers, strlen($headers));
}
while (true) {
$data = socket_read($client, 1024);
if ($data === false) break;
$decoded = decodeWebSocket($data);
echo "Received: {$decoded}\n";
$encoded = encodeWebSocket("Echo: {$decoded}");
socket_write($client, $encoded, strlen($encoded));
}
socket_close($client);
}
function decodeWebSocket($data) {
$length = ord($data[1]) & 127;
$mask = substr($data, 2, 4);
$payload = substr($data, 6);
$decoded = '';
for ($i = 0; $i < $length; $i++) {
$decoded .= $payload[$i] ^ $mask[$i % 4];
}
return $decoded;
}
function encodeWebSocket($text) {
$b1 = 0x80 | (0x1 & 0x0f);
$length = strlen($text);
$header = '';
if ($length <= 125) {
$header = pack('CC', $b1, $length);
} elseif ($length > 125 && $length < 65536) {
$header = pack('CCn', $b1, 126, $length);
} else {
$header = pack('CCNN', $b1, 127, $length);
}
return $header . $text;
}
这种方法需要手动处理 WebSocket 协议,适合学习 WebSocket 底层原理。
客户端连接示例
无论使用哪种服务器实现,客户端都可以通过以下 JavaScript 代码连接:
const socket = new WebSocket('ws://localhost:8080');
socket.onopen = () => console.log('Connected');
socket.onmessage = (e) => console.log('Received:', e.data);
socket.onclose = () => console.log('Disconnected');
socket.send('Hello, WebSocket!');
注意事项
- WebSocket 服务器需要长时间运行,建议使用 Supervisor 或 Systemd 管理进程。
- 生产环境建议使用成熟的库如 Ratchet 或 Swoole,避免手动实现协议。
- 注意处理连接异常和资源释放,避免内存泄漏。







