mita / uranus-socket-server
使用 Ratchet 构建的 PHP Socket 服务器库
Requires
- php: ^7.4 || ^8.0
- cboden/ratchet: ^0.4.3
- php-di/php-di: ^6.3
- symfony/config: ^5.4
- symfony/routing: ^5.0
- symfony/yaml: ^5.4
README
以下是 UranusSocketServer 文档的修订和结构化版本,包括配置路由、创建控制器以及建立连接后理解数据包结构的附加部分
UranusSocketServer
UranusSocketServer 是一个强大、可扩展且易于使用的 PHP 库,专为构建高性能 WebSocket 应用程序而设计。它具有灵活的中间件管道、全面的事件管理和高效连接处理等功能,让开发者能够轻松创建复杂的 WebSocket 解决方案。
功能
- 模块化架构:轻松扩展和自定义 WebSocket 服务器。
- 依赖注入:完全符合 DI 规范,代码干净且易于维护。
- 可扩展性:高效处理大量并发 WebSocket 连接。
- 自定义路由:支持中间件的路由消息到控制器。
- 事件驱动:挂钩到关键的生命周期事件以增强控制。
快速入门指南
1. 安装
使用 Composer 安装库
composer require mita/uranus-socket-server
2. 配置
2.1 设置路由
创建一个 routes.yaml
文件以定义您的 WebSocket 路由
join_room: path: /room/{roomId}/join controller: Mita\UranusSocketServer\Examples\Chat\Controllers\ChatController room_publish: path: /room/{roomId}/publish controller: Mita\UranusSocketServer\Examples\Chat\Controllers\ChatController
2.2 创建控制器
创建一个控制器以处理传入的 WebSocket 消息
<?php namespace Mita\UranusSocketServer\Examples\Chat\Controllers; use Mita\UranusSocketServer\Controllers\BaseController; use Mita\UranusSocketServer\Managers\ConnectionManager; use Mita\UranusSocketServer\Packets\PacketInterface; use Ratchet\ConnectionInterface; class ChatController extends BaseController { public function handle(ConnectionInterface $conn, PacketInterface $packet, array $params) { if ($params['_route'] === 'join_room') { $conn->send("You joined room " . $params['roomId']); } elseif ($params['_route'] === 'room_publish') { $conn->send("Message to room " . $params['roomId'] . ": " . $packet->getMessage()); } } }
2.3 理解数据包结构
向服务器发送数据时,数据包应结构化为至少包含两个键的 JSON 对象:route
和 msg
。
- route:指定数据包应发送到的 WebSocket 路由。
- msg:包含您希望发送的消息或数据。
示例数据包
{ "route": "/room/123/join", "msg": "Hello, I'm joining room 123" }
3. 运行基本聊天应用程序示例
本节演示了如何快速设置简单的 WebSocket 聊天服务器。
3.1 克隆仓库
git clone https://github.com/mita9497dev/uranus-socket-server.git
cd uranus-socket-server
3.2 安装依赖
composer install
3.3 导航到示例目录
cd examples/chat
3.4 index.php
简介
index.php
文件是 WebSocket 服务器的人口点。它使用基本设置初始化服务器
require __DIR__ . '/vendor/autoload.php'; use Mita\UranusSocketServer\SocketServer; $settings = [ 'host' => '127.0.0.1', 'port' => 7654, 'router_path' => __DIR__ . '/routes.yaml' ]; $socketServer = new SocketServer($settings); $socketServer->run();
3.5 运行 WebSocket 服务器
使用以下命令启动 WebSocket 服务器
php index.php
3.6 连接到服务器
使用 WebSocket 客户端连接到 ws://127.0.0.1:7654
并发送 JSON 数据包,如
加入房间
{ "route": "/room/123/join", "msg": "Joining room 123" }
向房间发送消息
{ "route": "/room/123/publish", "msg": "Hello, everyone!" }
4. 运行带有身份验证的聊天应用程序示例
此示例通过添加基于令牌的认证增强了基本的聊天功能。
4.1 克隆仓库
git clone https://github.com/mita9497dev/uranus-socket-server.git
cd uranus-socket-server
4.2 安装依赖
composer install
4.3 导航到示例目录
导航到 ChatWithAuth
示例目录
cd examples/ChatWithAuth
4.4 index.php
简介
在此示例中,index.php
文件注册了一个 AuthPlugin
用于基于令牌的认证
require __DIR__ . '/../../vendor/autoload.php'; use Mita\UranusSocketServer\Examples\ChatWithAuth\Plugins\AuthPlugin; use Mita\UranusSocketServer\SocketServer; $settings = [ 'host' => '127.0.0.1', 'port' => 7654, 'router_path' => __DIR__ . '/routes.yaml' ]; $socketServer = new SocketServer($settings); $authPlugin = new AuthPlugin('your_secret_key'); $socketServer->addPlugin($authPlugin); $socketServer->run();
此示例演示了如何创建和集成自定义插件。通过遵循此模式,您可以开发和注册插件以扩展服务器功能。
4.5 更新密钥
将 'your_secret_key'
替换为您希望的用于认证的密钥。
4.6 运行 WebSocket 服务器
启动 WebSocket 服务器
php index.php
4.7 连接到服务器
使用 WebSocket 客户端连接到 ws://127.0.0.1:7654
,包括在 URI 查询字符串中的 access_token
。
示例连接 URI
ws://127.0.0.1:7654/?access_token=your_secret_key
4.8 加入房间
使用以下JSON负载进行身份验证并加入聊天室
{ "route": "/room/123/join", "msg": "Joining room 123" }
4.9 向房间发送消息
身份验证并加入后,向房间发送消息
{ "route": "/room/123/publish", "msg": "Hello, authenticated users!" }
4.10 AuthPlugin.php
解释
AuthPlugin.php
文件是一个自定义插件,它将基于令牌的身份验证添加到您的WebSocket服务器中。以下是其关键部分的详细解释
class AuthPlugin implements PluginInterface, MiddlewareInterface { protected $secretKey; protected $keyName; // 1. Constructor public function __construct($secretKey, $keyName = 'access_token') { $this->secretKey = $secretKey; $this->keyName = $keyName; }
解释:构造函数使用一个密钥和一个令牌参数名称初始化插件。这种设置使您能够轻松配置要验证的令牌以及如何验证它。
// 2. Registering the Plugin public function register(EventDispatcherInterface $dispatcher) { $dispatcher->addListener('middleware.register', [$this, 'onRegisterMiddleware']); $dispatcher->addListener('connection.open', [$this, 'onOpen']); }
解释:register
方法通过监听特定事件(如 middleware.register
和 connection.open
)将插件钩入WebSocket服务器。这是将身份验证逻辑集成到服务器生命周期的地方。
// 3. Register Middleware public function onRegisterMiddleware(MiddlewarePipeline $pipeline) { $pipeline->add($this); }
解释:onRegisterMiddleware
方法将身份验证中间件添加到管道中。这确保每个通过服务器的消息都经过身份验证检查。
// 4. Connection Open Handler public function onOpen(ConnectionInterface $conn) { $uri = $conn->httpRequest->getUri(); parse_str($uri->getQuery(), $params); $token = $params[$this->keyName] ?? null; if (!$this->validateToken($token)) { $conn->send("Invalid token"); $conn->close(); throw new \Exception("Invalid token"); } }
解释:当打开一个新的WebSocket连接时,将调用 onOpen
方法。它从连接URI中提取令牌并进行验证。如果令牌无效,则立即关闭连接。
// 5. Message Handler Middleware public function handle(ConnectionInterface $conn, PacketInterface $packet, callable $next) { $token = $packet->getMetadata($this->keyName); if (!$this->validateToken($token)) { $conn->send("Invalid token"); $conn->close(); return; } $next($conn, $packet); }
解释:handle
方法处理传入的WebSocket消息。它检查消息元数据中的令牌,确保只有经过身份验证的用户才能与服务器交互。
// 6. Token Validation Method protected function validateToken($token) { if (!$token) { return false; } return $token == $this->secretKey; } }
解释:validateToken
方法是一个实用函数,用于将提供的令牌与密钥进行比较。如果需要,此简单方法可以扩展为更复杂的验证逻辑。
ChatWithAuth 示例的代码概述
ChatController.php
:处理房间加入和消息发布逻辑。AuthPlugin.php
:基于令牌的身份验证中间件。ChatService.php
:管理房间订阅和广播消息。index.php
:入口点,初始化WebSocket服务器并注册AuthPlugin
。routes.yaml
:定义加入和房间内消息的路由。
API 文档
1. SocketServer
SocketServer
类是您的WebSocket服务器的入口点。
-
run()
启动WebSocket服务器。
public function run()
-
registerEventListener(string $eventName, callable $listener)
注册事件监听器。
public function registerEventListener(string $eventName, callable $listener)
2. RoutingMiddleware
RoutingMiddleware
类处理传入WebSocket消息的路由。
-
handle(ConnectionInterface $conn, PacketInterface $packet, callable $next)
将消息路由到适当的控制器。
public function handle(ConnectionInterface $conn, PacketInterface $packet, callable $next)
3. MiddlewarePipeline
通过一系列中间件处理消息。
-
add(MiddlewareInterface $middleware)
将中间件添加到管道中。
public function add(MiddlewareInterface $middleware)
-
process(ConnectionInterface $conn, PacketInterface $packet, callable $finalHandler)
通过中间件管道处理数据包。
public function process(ConnectionInterface $conn, PacketInterface $packet, callable $finalHandler)
4. ConnectionManager
管理WebSocket连接及其订阅。
-
add(ConnectionInterface $conn)
添加新连接。
public function add(ConnectionInterface $conn)
-
remove(ConnectionInterface $conn)
删除连接。
public function remove(ConnectionInterface $conn)
5. EventDispatcher
管理事件监听器和事件分发。
-
addListener(string $eventName, callable $listener)
注册事件监听器。
public function addListener(string $eventName, callable $listener)
-
dispatch(string $eventName, $eventData = null)
将事件分发给注册的监听器。
public function dispatch(string $eventName, $eventData = null)
6. Packet
表示WebSocket消息数据包。
-
getRoute()
返回数据包的路由。
public function getRoute(): string
-
getMessage()
返回消息内容。
public function getMessage()
-
getMetadata(string $key = null)
返回元数据或特定键值。
public function getMetadata(string $key = null)
7. PacketFactory
从JSON字符串创建 Packet
实例。
-
createFromJson(string $json): PacketInterface
从JSON字符串创建一个
Packet
。public function createFromJson(string $json): PacketInterface
8. PluginManager
管理系统插件的生命周期。
-
addPlugin(PluginInterface $plugin)
将插件添加到管理器。
public function addPlugin(PluginInterface $plugin)
-
registerPlugins(EventDispatcherInterface $dispatcher)
将所有插件注册到事件调度器,并触发
plugin.registered
事件。public function registerPlugins(EventDispatcherInterface $dispatcher)
-
bootPlugins()
启动所有已注册的插件。
public function bootPlugins()
创建插件
要在UranusSocketServer中创建插件,您需要实现PluginInterface
。插件可以用于向服务器添加自定义功能,例如身份验证、日志记录或其他中间件。以下是创建和注册插件的简要概述
- 实现
PluginInterface
use Mita\UranusSocketServer\Events\EventDispatcherInterface; use Mita\UranusSocketServer\Plugins\PluginInterface; class MyCustomPlugin implements PluginInterface { public function register(EventDispatcherInterface $dispatcher) { // Register events or middleware here } public function boot() { // Code to run when the plugin is booted } public function unregister(EventDispatcherInterface $dispatcher) { // Unregister events or middleware here } }
- 将插件添加到服务器
$myPlugin = new MyCustomPlugin(); $socketServer->addPlugin($myPlugin);
通过遵循此模式,您可以扩展WebSocket服务器的功能,以满足您的特定需求。
事件文档
概述
UranusSocketServer库提供了一种强大的基于事件的架构,允许您挂钩WebSocket服务器各种生命周期事件。本节介绍了可用的事件、触发它们的上下文、它们提供的参数以及如何使用它们的示例。
1. connection.opened
- 描述:当建立新的WebSocket连接时触发。
- 上下文:在
WebSocketService::onOpen
中触发。 - 参数
ConnectionInterface $conn
:表示新的连接。
- 示例
$socketServer->registerEventListener('connection.opened', function($conn) { echo "New connection opened with ID: " . $conn->resourceId . "\n"; });
2. message.received
- 描述:当接收到WebSocket消息时触发。
- 上下文:在
WebSocketService::onMessage
中触发。 - 参数
ConnectionInterface $connection
:接收消息的连接实例。string $message
:实际的消息内容。
- 示例
$socketServer->registerEventListener('message.received', function($data) { $conn = $data['connection']; $msg = $data['message']; echo "Message received from connection {$conn->resourceId}: {$msg}\n"; });
3. plugin.registered
- 描述:当在系统中注册插件时触发。
- 上下文:在
PluginManager::registerPlugins
中触发。 - 参数
PluginInterface $plugin
:已注册的插件实例。
- 示例
$socketServer->registerEventListener('plugin.registered', function($plugin) { echo "Plugin registered: " . get_class($plugin) . "\n"; });
4. connection.added
- 描述:当WebSocket连接添加到ConnectionManager时触发。
- 上下文:在
ConnectionManager::add
中触发。 - 参数
ConnectionInterface $conn
:被添加的连接对象。
- 示例
$socketServer->registerEventListener('connection.added', function($conn) { echo "Connection added with ID: " . $conn->resourceId . "\n"; });
5. connection.removed
- 描述:当WebSocket连接从ConnectionManager中删除时触发。
- 上下文:在
ConnectionManager::remove
中触发。 - 参数
ConnectionInterface $conn
:被删除的连接对象。
- 示例
$socketServer->registerEventListener('connection.removed', function($conn) { echo "Connection removed with ID: " . $conn->resourceId . "\n"; });
6. connection.subscribed
- 描述:当连接订阅特定路由时触发。
- 上下文:在
ConnectionManager::subscribe
中触发。 - 参数
ConnectionInterface $conn
:订阅的连接。string $route
:连接订阅的路由。
- 示例
$socketServer->registerEventListener('connection.subscribed', function($data) { $conn = $data['conn']; $route = $data['route']; echo "Connection {$conn->resourceId} subscribed to route: {$route}\n"; });
7. connection.unsubscribed
- 描述:当连接取消订阅特定路由时触发。
- 上下文:在
ConnectionManager::unsubscribe
中触发。 - 参数
ConnectionInterface $conn
:取消订阅的连接。string $route
:连接取消订阅的路由。
- 示例
$socketServer->registerEventListener('connection.unsubscribed', function($data) { $conn = $data['conn']; $route = $data['route']; echo "Connection {$conn->resourceId} unsubscribed from route: {$route}\n"; });
8. message.sent
- 描述:当将消息发送到特定路由的所有订阅者时触发。
- 上下文:在
ConnectionManager::sendToRoute
中触发。 - 参数
string $route
:消息发送到的路由。string $message
:发送的消息内容。
- 示例
$socketServer->registerEventListener('message.sent', function($data) { $route = $data['route']; $message = $data['message']; echo "Message sent to route {$route}: {$message}\n"; });
感谢您使用UranusSocketServer!希望它可以帮助您轻松构建下一个WebSocket应用程序。如果您有任何问题或需要支持,请随时打开一个问题或联系社区。
编码愉快!