# wk-proto-php **Repository Path**: Dongasai/wk-proto-php ## Basic Information - **Project Name**: wk-proto-php - **Description**: WuKongIM协议PHP实现 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-09-07 - **Last Updated**: 2025-09-13 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WkProtoPHP - WuKongIM协议PHP实现 WkProtoPHP是[WuKongIM](https://github.com/WuKongIM/WuKongIMGoProto)二进制协议的完整PHP实现,提供了高效的协议编解码功能。 ## ✨ 特性 - 🚀 **高性能二进制协议解析** - 原生PHP实现,无外部依赖 - 🔒 **完整的协议类型支持** - 支持所有WuKongIM协议包类型 - 📦 **简单易用的API** - 直观的面向对象接口 - 🛡️ **完善的错误处理** - 详细的错误信息和异常处理 - 🧪 **全面的测试覆盖** - 每个包都有独立的测试用例 - 📚 **详细的使用文档** - 完整的API文档和示例代码 - 🔄 **版本兼容性** - 支持协议版本5,向后兼容 - 🎯 **Go版本兼容** - 与Go版本完全兼容,可互操作 - 📋 **JSON序列化支持** - 完整的JSON互相转换功能 ## 📋 支持的协议包 ### 连接管理 - ✅ **CONNECT** - 客户端连接请求 - ✅ **CONNACK** - 服务端连接确认 - ✅ **DISCONNECT** - 断开连接 - ✅ **PING/PONG** - 心跳保活 ### 消息传输 - ✅ **SEND** - 发送消息 - ✅ **SENDACK** - 发送确认 - ✅ **RECV** - 接收消息 - ✅ **RECVACK** - 接收确认 ### 高级功能 - ✅ **JSON序列化** - 完整的JSON互相转换功能 - ✅ **SUB/SUBACK** - 订阅管理 - ✅ **EVENT** - 事件处理 ## 🚀 安装 ### 直接使用 ```bash git clone https://github.com/your-repo/WkProtoPHP.git cd WkProtoPHP ``` ### 通过Composer(推荐) ```bash composer require dongasai/wk-proto-php ``` ## 🎯 快速开始 ### 基本使用 ```php setVersion(5); $connectPacket->setUid('user_123456'); $connectPacket->setToken('your_token_here'); $connectPacket->setDeviceId('device_001'); $connectPacket->setDeviceFlag(DeviceFlag::APP); $connectPacket->setClientTimestamp(time() * 1000); $connectPacket->setClientKey('your_client_key'); // 编码数据包 $encodedData = $protocol->encodeFrame($connectPacket); // 解码数据包 [$decodedPacket, $length, $error] = $protocol->decodeFrame($encodedData); if ($error) { echo "解码失败: " . $error->getMessage(); } else { echo "解码成功: " . $decodedPacket; } ``` ### 发送消息 ```php set(Setting::RECEIPT_ENABLED); // 启用回执 $sendPacket->setSetting($setting); // 设置消息内容 $sendPacket->setMsgKey('unique_msg_key_' . time()); $sendPacket->setClientSeq(1); $sendPacket->setClientMsgNo('msg_' . uniqid()); $sendPacket->setChannelId('user_002'); $sendPacket->setChannelType(ChannelType::PERSON); $sendPacket->setPayload('你好,这是一条测试消息!'); // 编码并发送 $encodedMessage = $protocol->encodeFrame($sendPacket); ``` ### JSON序列化 所有协议包都支持JSON序列化和反序列化,便于数据存储和传输: ```php setSetting(new Setting(1)); $recvPacket->setMsgKey('test_msg_key'); $recvPacket->setFromUid('user_123456'); $recvPacket->setChannelId('channel_001'); $recvPacket->setChannelType(1); $recvPacket->setPayload('Hello, World!'); $recvPacket->setMessageId(123456789); $recvPacket->setMessageSeq(987654321); $recvPacket->setTimestamp(1640995200); // 转换为JSON $json = $recvPacket->toJson(); echo $json; // 输出: // { // "setting": 1, // "msgKey": "test_msg_key", // "expire": 0, // "messageId": 123456789, // "messageSeq": 987654321, // "clientMsgNo": "", // "streamNo": "", // "streamId": 0, // "streamFlag": 0, // "timestamp": 1640995200, // "channelId": "channel_001", // "channelType": 1, // "topic": "", // "fromUid": "user_123456", // "payload": "Hello, World!", // "clientSeq": 0 // } // 从JSON恢复对象 $restoredPacket = RecvPacket::fromJson($json); echo "FromUID: " . $restoredPacket->getFromUid() . "\n"; echo "Payload: " . $restoredPacket->getPayload() . "\n"; // 转换为数组 $array = $recvPacket->toArray(); echo "MessageID: " . $array['messageId'] . "\n"; // 从数组创建对象 $fromArray = RecvPacket::fromArray($array); echo "ChannelID: " . $fromArray->getChannelId() . "\n"; ``` #### 批量JSON处理 ```php // 批量处理多个包 $packets = []; for ($i = 1; $i <= 3; $i++) { $packet = new RecvPacket(); $packet->setSetting(new Setting($i)); $packet->setMsgKey("batch_msg_$i"); $packet->setFromUid("user_$i"); $packet->setChannelId("channel_$i"); $packet->setChannelType(1); $packet->setPayload("Batch message $i"); $packet->setMessageId($i * 1000); $packet->setTimestamp(1640995200 + $i); $packets[] = $packet; } // 批量转换为JSON数组 $jsonArray = array_map(function($packet) { return json_decode($packet->toJson(), true); }, $packets); echo json_encode($jsonArray, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); // 批量从JSON恢复 $restoredPackets = array_map(function($jsonData) { return RecvPacket::fromJson(json_encode($jsonData)); }, $jsonArray); echo "恢复的包数量: " . count($restoredPackets) . "\n"; ``` #### 数据持久化 ```php // 保存包到文件 function savePacketToFile(Packet $packet, string $filename): void { $json = $packet->toJson(); file_put_contents($filename, $json); } // 从文件加载包 function loadPacketFromFile(string $filename): Packet { $json = file_get_contents($filename); return RecvPacket::fromJson($json); } // 使用示例 $packet = new RecvPacket(); $packet->setSetting(new Setting(1)); $packet->setFromUid('user_001'); $packet->setChannelId('channel_001'); $packet->setPayload('Persistent message'); // 保存到文件 savePacketToFile($packet, 'message.json'); // 从文件加载 $loadedPacket = loadPacketFromFile('message.json'); echo "加载的消息: " . $loadedPacket->getPayload() . "\n"; ``` ## 📚 协议包详解 ### CONNECT包 客户端连接时使用的包,包含用户认证信息: ```php $connectPacket = new ConnectPacket(); $connectPacket->setVersion(5); // 协议版本 $connectPacket->setUid('user_001'); // 用户ID $connectPacket->setToken('auth_token'); // 认证令牌 $connectPacket->setDeviceId('device_001'); // 设备ID $connectPacket->setDeviceFlag(DeviceFlag::APP); // 设备类型 $connectPacket->setClientTimestamp(time() * 1000); // 客户端时间戳 $connectPacket->setClientKey('encryption_key'); // 加密密钥 ``` ### SEND包 发送消息时使用的包: ```php $sendPacket = new SendPacket(); $sendPacket->setClientSeq(1); // 客户端序列号 $sendPacket->setClientMsgNo('msg_001'); // 消息唯一ID $sendPacket->setChannelId('channel_001'); // 频道ID $sendPacket->setChannelType(ChannelType::PERSON); // 频道类型 $sendPacket->setPayload('消息内容'); // 消息内容 ``` ### Setting配置 消息设置标志位,用于控制消息行为: ```php $setting = new Setting(); $setting->set(Setting::RECEIPT_ENABLED); // 启用回执 $setting->set(Setting::TOPIC); // 包含话题 $setting->set(Setting::NO_ENCRYPT); // 不加密 $setting->set(Setting::STREAM); // 流消息 ``` ### SUB包 订阅管理包,用于订阅或取消订阅频道: ```php $subPacket = new SubPacket(); $subPacket->setSetting(new Setting(1)); // 消息设置 $subPacket->setSubNo('sub_001'); // 订阅编号 $subPacket->setChannelId('channel_001'); // 频道ID $subPacket->setChannelType(ChannelType::GROUP); // 频道类型 $subPacket->setAction(Action::Subscribe); // 订阅动作 $subPacket->setParam('subscribe_param'); // 订阅参数 ``` ### SUBACK包 订阅确认包,服务端响应订阅请求: ```php $subackPacket = new SubackPacket(); $subackPacket->setSubNo('sub_001'); // 订阅编号 $subackPacket->setChannelId('channel_001'); // 频道ID $subackPacket->setChannelType(ChannelType::GROUP); // 频道类型 $subackPacket->setAction(Action::Subscribe); // 订阅动作 $subackPacket->setReasonCode(ReasonCode::Success); // 响应码 ``` ### EVENT包 事件处理包,用于系统事件通知: ```php $eventPacket = new EventPacket(); $eventPacket->setId('event_001'); // 事件ID $eventPacket->setType('user_online'); // 事件类型 $eventPacket->setTimestamp(time()); // 事件时间戳 $eventPacket->setData(json_encode([ // 事件数据 'user_id' => 'user_001', 'status' => 'online' ])); ``` ## 🔧 常量定义 ### 设备类型 (DeviceFlag) ```php DeviceFlag::APP // 移动应用 DeviceFlag::WEB // Web端 DeviceFlag::PC // PC端 DeviceFlag::UNKNOWN // 未知设备 ``` ### 频道类型 (ChannelType) ```php ChannelType::PERSON // 个人频道 ChannelType::GROUP // 群组频道 ChannelType::CUSTOMER_SERVICE // 客服频道 ChannelType::COMMUNITY // 社区频道 ChannelType::INFO // 资讯频道 ChannelType::DATA // 数据频道 ChannelType::TEMP // 临时频道 ChannelType::LIVE // 直播频道 ``` ### 订阅动作 (Action) ```php Action::Subscribe // 订阅 Action::UnSubscribe // 取消订阅 ``` ### 原因码 (ReasonCode) ```php ReasonCode::SUCCESS // 成功 ReasonCode::AUTH_FAIL // 认证失败 ReasonCode::RATE_LIMIT // 速率限制 ReasonCode::SYSTEM_ERROR // 系统错误 // ... 更多原因码 ``` ## 🧪 测试 ### 运行所有测试 ```bash php tests/run_all_tests.php ``` ### 运行单个包测试 ```bash # 测试CONNECT包 php tests/ConnectPacketTest.php # 测试SEND包 php tests/SendPacketTest.php # 测试RECV包 php tests/RecvPacketTest.php # 测试JSON转换功能 php vendor/bin/phpunit tests/PHPUnit/JsonSerializableTest.php ``` ### JSON转换测试示例 ```bash # 运行JSON序列化测试 php vendor/bin/phpunit tests/PHPUnit/JsonSerializableTest.php --filter testRecvPacketJsonConversion # 测试JSON格式化 php vendor/bin/phpunit tests/PHPUnit/JsonSerializableTest.php --filter testJsonFormatting # 测试批量JSON处理 php vendor/bin/phpunit tests/PHPUnit/JsonSerializableTest.php --filter testEmptyObjectJsonConversion ``` ### 测试输出示例 ``` Testing CONNECT packet... Original CONNECT packet: CONNECT UID:test_user_001 DeviceFlag:0 DeviceId:device_001 ClientTimestamp:1757178512000 Token:test_token_123 Version:5 CONNECT encoded data length: 87 CONNECT encoded data (hex): 10550500000a6465766963655f303031000d746573745f757365725f303031000e746573745f746f6b656e5f3132330000019920004280001e746573745f636c69656e745f6b65795f6261736536345f656e636f646564 CONNECT decoded successfully: CONNECT UID:test_user_001 DeviceFlag:0 DeviceId:device_001 ClientTimestamp:1757178512000 Token:test_token_123 Version:5 ``` ## 💡 完整客户端示例 ```php protocol = new Protocol(); } /** * 连接到服务器 */ public function connect($host, $port, $uid, $token) { // 创建socket连接 $this->socket = fsockopen($host, $port, $errno, $errstr, 30); if (!$this->socket) { throw new Exception("连接失败: $errstr ($errno)"); } // 发送连接包 $connectPacket = new ConnectPacket(); $connectPacket->setVersion(5); $connectPacket->setUid($uid); $connectPacket->setToken($token); $connectPacket->setDeviceId('php_client_' . uniqid()); $connectPacket->setDeviceFlag(DeviceFlag::PC); $connectPacket->setClientTimestamp(time() * 1000); $connectPacket->setClientKey('client_key_' . md5($uid . $token)); $data = $this->protocol->encodeFrame($connectPacket); fwrite($this->socket, $data); // 等待连接确认 $response = fread($this->socket, 1024); [$connack, $length, $error] = $this->protocol->decodeFrame($response); if ($error || !($connack instanceof ConnackPacket)) { throw new Exception("连接认证失败"); } $this->connected = true; echo "连接成功!\n"; // 启动心跳 $this->startHeartbeat(); // 启动消息接收 $this->startMessageReceiver(); } /** * 发送消息 */ public function sendMessage($toUid, $message) { if (!$this->connected) { throw new Exception("未连接到服务器"); } $sendPacket = new SendPacket(); $setting = new Setting(); $setting->set(Setting::RECEIPT_ENABLED); $sendPacket->setSetting($setting); $sendPacket->setClientSeq(++$this->clientSeq); $sendPacket->setClientMsgNo('msg_' . uniqid()); $sendPacket->setChannelId($toUid); $sendPacket->setChannelType(ChannelType::PERSON); $sendPacket->setPayload($message); $data = $this->protocol->encodeFrame($sendPacket); fwrite($this->socket, $data); echo "消息已发送\n"; // 保存消息到历史记录 $this->saveMessageToHistory($sendPacket); } /** * 保存消息到历史记录 */ private function saveMessageToHistory($packet) { $historyFile = 'message_history.json'; $messages = []; // 读取现有消息历史 if (file_exists($historyFile)) { $json = file_get_contents($historyFile); $messages = json_decode($json, true) ?: []; } // 添加新消息(使用JSON序列化) $messages[] = json_decode($packet->toJson(), true); // 保存到文件 file_put_contents($historyFile, json_encode($messages, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)); } /** * 加载消息历史 */ public function loadMessageHistory() { $historyFile = 'message_history.json'; if (!file_exists($historyFile)) { return []; } $json = file_get_contents($historyFile); $messages = json_decode($json, true) ?: []; // 从JSON恢复消息对象 return array_map(function($msgData) { return SendPacket::fromJson(json_encode($msgData)); }, $messages); } /** * 启动心跳 */ private function startHeartbeat() { // 定期发送PING包 register_tick_function(function() { if ($this->connected) { $pingPacket = new PingPacket(); $data = $this->protocol->encodeFrame($pingPacket); fwrite($this->socket, $data); } }); } /** * 启动消息接收 */ private function startMessageReceiver() { // 监听服务器消息 stream_set_blocking($this->socket, false); register_tick_function(function() { if ($this->connected) { $data = fread($this->socket, 8192); if ($data) { [$packet, $length, $error] = $this->protocol->decodeFrame($data); if (!$error && $packet instanceof RecvPacket) { echo "收到消息: " . $packet->getPayload() . "\n"; // 发送接收确认 $recvackPacket = new RecvackPacket(); $recvackPacket->setMessageId($packet->getMessageId()); $recvackPacket->setMessageSeq($packet->getMessageSeq()); $ackData = $this->protocol->encodeFrame($recvackPacket); fwrite($this->socket, $ackData); } } } }); } /** * 断开连接 */ public function disconnect() { if ($this->connected) { $disconnectPacket = new DisconnectPacket(); $disconnectPacket->setReasonCode(ReasonCode::SUCCESS); $disconnectPacket->setReason('Client disconnect'); $data = $this->protocol->encodeFrame($disconnectPacket); fwrite($this->socket, $data); fclose($this->socket); $this->connected = false; echo "连接已断开\n"; } } } // 使用示例 $client = new WuKongIMClient(); try { $client->connect('127.0.0.1', 5100, 'user_001', 'your_token'); $client->sendMessage('user_002', '你好,这是一条测试消息!'); $client->sendMessage('user_002', '这是第二条消息!'); // 演示JSON功能 echo "\n=== JSON功能演示 ===\n"; // 加载消息历史 $history = $client->loadMessageHistory(); echo "消息历史记录数量: " . count($history) . "\n"; foreach ($history as $i => $msg) { echo "消息 " . ($i + 1) . ": " . $msg->getPayload() . "\n"; } // 创建新消息并转换为JSON $newMsg = new SendPacket(); $newMsg->setClientSeq(999); $newMsg->setClientMsgNo('demo_msg'); $newMsg->setChannelId('demo_channel'); $newMsg->setChannelType(ChannelType::PERSON); $newMsg->setPayload('JSON演示消息'); echo "\n新消息JSON格式:\n"; echo $newMsg->toJson() . "\n"; // 保持运行 while (true) { sleep(1); } } catch (Exception $e) { echo "错误: " . $e->getMessage() . "\n"; } ``` ## 🚀 性能优化 ### 批量处理 ```php // 批量编码多个包 $packets = [$packet1, $packet2, $packet3]; $batchData = ''; foreach ($packets as $packet) { $batchData .= $protocol->encodeFrame($packet); } // 一次性发送 fwrite($socket, $batchData); ``` ### 连接池 ```php class ConnectionPool { private $connections = []; public function getConnection($key) { if (!isset($this->connections[$key])) { $this->connections[$key] = new WuKongIMClient(); $this->connections[$key]->connect($host, $port, $uid, $token); } return $this->connections[$key]; } } ``` ## 🛡️ 错误处理 ```php try { [$packet, $length, $error] = $protocol->decodeFrame($data); if ($error) { throw new Exception("解码失败: " . $error->getMessage()); } // 处理解码后的包 $this->handlePacket($packet); } catch (Exception $e) { error_log("协议处理错误: " . $e->getMessage()); // 错误恢复逻辑 } ``` ## 📖 协议结构 ### 消息格式 ``` [固定头部(2字节)][可变长度编码][可变头部][Payload] ``` 详细协议规范请参考 [protocol.md](protocol.md)。 ## 开发 ### 运行测试 ```bash # 运行所有测试 php tests/run_all_tests.php # 运行特定包测试 php tests/ConnectPacketTest.php php tests/SendPacketTest.php # 使用Composer(如果已配置) composer test ``` ### 代码规范 ```bash # 检查代码规范 composer cs-check # 自动修复代码规范 composer cs-fix ``` ### 调试技巧 #### 启用详细日志 ```php $protocol = new Protocol(); $protocol->setDebugMode(true); // 启用调试模式 // 编码时显示详细信息 $encodedData = $protocol->encodeFrame($packet); echo "编码数据长度: " . strlen($encodedData) . " 字节\n"; echo "编码数据 (hex): " . bin2hex($encodedData) . "\n"; // 解码时显示解析过程 [$packet, $length, $error] = $protocol->decodeFrame($data); if ($error) { echo "解码错误: " . $error->getMessage() . "\n"; echo "错误代码: " . $error->getCode() . "\n"; } ``` #### 数据包验证 ```php // 验证数据包完整性 public function validatePacket(FrameInterface $packet): bool { try { // 尝试编码解码循环 $encoded = $this->protocol->encodeFrame($packet); [$decoded, $length, $error] = $this->protocol->decodeFrame($encoded); if ($error) { echo "验证失败: " . $error->getMessage() . "\n"; return false; } return $packet->getFrameType() === $decoded->getFrameType(); } catch (Exception $e) { echo "验证异常: " . $e->getMessage() . "\n"; return false; } } ``` ### 性能分析 ```php // 性能测试示例 $startTime = microtime(true); // 批量编码测试 $packets = []; for ($i = 0; $i < 1000; $i++) { $packet = new SendPacket(); $packet->setClientSeq($i); $packet->setClientMsgNo('msg_' . $i); $packet->setChannelId('user_' . ($i % 10)); $packet->setChannelType(ChannelType::PERSON); $packet->setPayload('测试消息 ' . $i); $packets[] = $packet; } $encodedData = ''; foreach ($packets as $packet) { $encodedData .= $protocol->encodeFrame($packet); } $endTime = microtime(true); echo "编码1000个包耗时: " . round(($endTime - $startTime) * 1000, 2) . " ms\n"; echo "总数据大小: " . strlen($encodedData) . " 字节\n"; echo "平均每个包: " . round(strlen($encodedData) / 1000, 2) . " 字节\n"; ``` ## 🚨 故障排除 ### 常见问题 #### 1. 编码/解码失败 **问题**: `解码失败: Invalid frame type` 或 `编码失败: Data too large` **解决方案**: ```php // 检查数据包类型 if ($packet->getFrameType() === FrameType::UNKNOWN) { throw new Exception("未知的数据包类型"); } // 检查数据大小 $maxSize = Protocol::MAX_REMAINING_LENGTH; if (strlen($data) > $maxSize) { throw new Exception("数据超过最大限制: " . $maxSize . " 字节"); } // 检查协议版本 if ($packet->getVersion() > Protocol::LATEST_VERSION) { throw new Exception("不支持的协议版本: " . $packet->getVersion()); } ``` #### 2. 连接认证失败 **问题**: CONNACK返回错误码 **解决方案**: ```php // 检查CONNACK响应 if ($connack->getReasonCode() !== ReasonCode::SUCCESS) { $errorMsg = match($connack->getReasonCode()) { ReasonCode::AUTH_FAIL => "认证失败,请检查token", ReasonCode::RATE_LIMIT => "请求过于频繁,请稍后重试", ReasonCode::SYSTEM_ERROR => "系统错误,请联系管理员", default => "未知错误: " . $connack->getReasonCode() }; throw new Exception($errorMsg); } ``` #### 3. 内存溢出 **问题**: 处理大量消息时内存不足 **解决方案**: ```php // 分批处理消息 function processMessagesInBatches(array $messages, int $batchSize = 100) { foreach (array_chunk($messages, $batchSize) as $batch) { foreach ($batch as $message) { $packet = $this->createPacketFromMessage($message); $encoded = $this->protocol->encodeFrame($packet); // 发送数据... } // 手动触发垃圾回收 if (function_exists('gc_collect_cycles')) { gc_collect_cycles(); } } } // 限制内存使用 ini_set('memory_limit', '512M'); ``` #### 4. 网络连接问题 **问题**: Socket连接超时或断开 **解决方案**: ```php // 设置socket超时 stream_set_timeout($socket, 30); // 30秒超时 // 检查连接状态 $socketStatus = socket_get_status($socket); if ($socketStatus['timed_out']) { throw new Exception("连接超时"); } if ($socketStatus['eof']) { throw new Exception("连接已断开"); } // 重连机制 function reconnectWithBackoff($maxRetries = 5) { $retryCount = 0; $backoffTime = 1; // 初始1秒 while ($retryCount < $maxRetries) { try { return $this->connect(); } catch (Exception $e) { $retryCount++; if ($retryCount >= $maxRetries) { throw $e; } sleep($backoffTime); $backoffTime *= 2; // 指数退避 } } } ``` ### 调试工具 #### 协议分析器 ```php class ProtocolAnalyzer { private Protocol $protocol; public function analyzeData(string $data): array { $analysis = [ 'total_length' => strlen($data), 'packets' => [] ]; $offset = 0; while ($offset < strlen($data)) { $chunk = substr($data, $offset); [$packet, $length, $error] = $this->protocol->decodeFrame($chunk); if ($error) { $analysis['error'] = $error->getMessage(); break; } $analysis['packets'][] = [ 'type' => $packet->getFrameType(), 'type_name' => FrameType::toString($packet->getFrameType()), 'length' => $length, 'offset' => $offset, 'packet' => $packet ]; $offset += $length; } return $analysis; } } ``` #### 数据包监控 ```php class PacketMonitor { private array $stats = [ 'encoded' => 0, 'decoded' => 0, 'errors' => 0, 'bytes_sent' => 0, 'bytes_received' => 0 ]; public function encodeWithMonitor(FrameInterface $packet): string { try { $data = $this->protocol->encodeFrame($packet); $this->stats['encoded']++; $this->stats['bytes_sent'] += strlen($data); return $data; } catch (Exception $e) { $this->stats['errors']++; throw $e; } } public function decodeWithMonitor(string $data): array { try { [$packet, $length, $error] = $this->protocol->decodeFrame($data); if ($error) { throw $error; } $this->stats['decoded']++; $this->stats['bytes_received'] += $length; return [$packet, $length, null]; } catch (Exception $e) { $this->stats['errors']++; throw $e; } } public function getStats(): array { return $this->stats; } } ``` ## 📊 性能基准 ### 基准测试结果 在标准开发环境下的性能表现: ``` 编码性能: - CONNECT包: ~0.05ms/包 - SEND包: ~0.03ms/包 - RECV包: ~0.03ms/包 - PING包: ~0.01ms/包 解码性能: - CONNECT包: ~0.06ms/包 - SEND包: ~0.04ms/包 - RECV包: ~0.04ms/包 - PING包: ~0.01ms/包 内存使用: - 基础内存: ~2MB - 每个连接: ~50KB - 1000并发连接: ~52MB ``` ### 优化建议 1. **批量处理**: 尽量批量编码/解码数据包 2. **连接池**: 复用连接减少创建开销 3. **内存管理**: 及时清理不再使用的数据包 4. **缓存**: 缓存常用的协议对象 5. **异步处理**: 使用异步I/O提高并发性能 ## 🤝 贡献 欢迎提交 Issue 和 Pull Request! ### 开发流程 1. Fork 本仓库 2. 创建特性分支 (`git checkout -b feature/AmazingFeature`) 3. 提交更改 (`git commit -m 'Add some AmazingFeature'`) 4. 推送到分支 (`git push origin feature/AmazingFeature`) 5. 创建 Pull Request ### 代码规范 - 遵循 PSR-4 自动加载标准 - 使用 PSR-12 编码规范 - 添加适当的注释和文档 - 编写测试用例 ## 📄 许可证 MIT License - 详见 [LICENSE](LICENSE) 文件 ## 📞 联系方式 - 作者: dongasai - 邮箱: 1514582970@qq.com - 项目地址: [GitHub Repository](https://github.com/your-repo/WkProtoPHP) --- ## 🙏 致谢 感谢 [WuKongIM](https://github.com/WuKongIM/WuKongIMGoProto) 项目提供的优秀协议规范和Go实现。