feat: 实现TCP Server

This commit is contained in:
zimoyin
2026-03-02 21:59:43 +08:00
parent 043306819b
commit a79dfae57d
144 changed files with 15785 additions and 140 deletions
@@ -0,0 +1,36 @@
<?php
namespace app\net\parsers;
/**
* 电流采集器报文解析器(长度78)
*/
class CurrentCollectorParser implements PacketParserInterface
{
public function supports(string $hexString): bool
{
return strlen($hexString) === 78;
}
public function parse(string $hexString): array
{
$pattern = '/^BBBB([0-9A-F]{12})([0-9A-F]{10})([0-9A-F]{10})(24[0-9A-F]{8})(01[0-9A-F]{2})(02[0-9A-F]{2})(03[0-9A-F]{2})(04[0-9A-F]{2})(05[0-9A-F]{2})(06[0-9A-F]{2})([0-9A-F]{8})$/';
if (preg_match($pattern, $hexString, $matches)) {
return [
'hexType' => 3,
'isMatched' => true,
'card' => $matches[3],
'reader' => $matches[2],
'detectionDevice' => $matches[4],
'channel1' => $matches[5],
'channel2' => $matches[6],
'channel3' => $matches[7],
'channel4' => $matches[8],
'channel5' => $matches[9],
'channel6' => $matches[10],
];
}
return ['isMatched' => false];
}
}
@@ -0,0 +1,25 @@
<?php
namespace app\net\parsers;
/**
* 新版电流采集器报文解析器(长度38)
*/
class NewCurrentCollectorParser implements PacketParserInterface
{
public function supports(string $hexString): bool
{
return strlen($hexString) === 38;
}
public function parse(string $hexString): array
{
return [
'hexType' => 4,
'isMatched' => true,
'detectionDevice' => substr($hexString, 16, 2),
'channel1' => substr($hexString, 24, 2),
];
}
}
+106
View File
@@ -0,0 +1,106 @@
<?php
namespace app\net\parsers;
use app\net\Packet;
/**
* 报文解析器工厂(单例模式)
*/
class PacketParserFactory
{
/**
* @var self|null 单例实例
*/
private static ?self $instance = null;
/**
* @var PacketParserInterface[] 解析器列表
*/
private array $parsers = [];
/**
* 私有化构造函数(禁止外部 new)
*/
private function __construct()
{
$this->registerDefaultParsers();
}
/**
* 防止克隆(保障单例唯一性)
*/
private function __clone() {}
/**
* 防止反序列化(保障单例唯一性)
*/
public function __wakeup()
{
throw new \RuntimeException('Cannot unserialize singleton ' . self::class);
}
/**
* 获取单例实例(懒汉式:首次调用才初始化)
* @return self
*/
public static function getInstance(): self
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
/**
* 注册默认解析器(抽离出来,便于扩展)
*/
private function registerDefaultParsers(): void
{
$this->registerParser(new WiredReaderParser());
$this->registerParser(new WirelessReaderParser());
$this->registerParser(new CurrentCollectorParser());
$this->registerParser(new NewCurrentCollectorParser());
}
/**
* 注册解析器(支持动态扩展)
* @param PacketParserInterface $parser
* @return void
*/
public function registerParser(PacketParserInterface $parser): void
{
$this->parsers[] = $parser;
}
/**
* 创建并解析Packet对象
* @param string $rawBytes 原始报文字节数据
* @return Packet
*/
public function create(string $rawBytes): Packet
{
$hexString = strtoupper(bin2hex($rawBytes));
$parsedData = null;
// 遍历解析器找匹配的
foreach ($this->parsers as $parser) {
if ($parser->supports($hexString)) {
$parsedData = $parser->parse($hexString);
break;
}
}
return new Packet($rawBytes, $parsedData);
}
/**
* 创建并解析Packet对象
* @param string $rawBytes 原始报文字节数据
* @return Packet
*/
public static function new(string $rawBytes): Packet
{
return self::getInstance()->create($rawBytes);
}
}
+23
View File
@@ -0,0 +1,23 @@
<?php
namespace app\net\parsers;
/**
* 报文解析器接口
*/
interface PacketParserInterface
{
/**
* 判断当前解析器是否支持该报文
* @param string $hexString 十六进制字符串
* @return bool
*/
public function supports(string $hexString): bool;
/**
* 解析报文并返回填充好的属性数组
* @param string $hexString 十六进制字符串
* @return array 解析后的属性数组(key为属性名,value为属性值)
*/
public function parse(string $hexString): array;
}
+30
View File
@@ -0,0 +1,30 @@
<?php
namespace app\net\parsers;
use app\net\parsers\PacketParserInterface;
/**
* 有线读卡器报文解析器(长度20)
*/
class WiredReaderParser implements PacketParserInterface
{
public function supports(string $hexString): bool
{
return strlen($hexString) === 20;
}
public function parse(string $hexString): array
{
$pattern = '/(09[a-fA-F0-9]{8})([a-fA-F0-9]{10})/';
if (preg_match($pattern, $hexString, $matches)) {
return [
'hexType' => 1,
'isMatched' => true,
'reader' => $matches[1],
'card' => $matches[2],
];
}
return ['isMatched' => false];
}
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace app\net\parsers;
/**
* 无线读卡器报文解析器(长度56)
*/
class WirelessReaderParser implements PacketParserInterface
{
public function supports(string $hexString): bool
{
return strlen($hexString) === 56;
}
public function parse(string $hexString): array
{
$pattern = '/^5A(.{12})(.{26})(.{12})(.{2})A5$/';
if (preg_match($pattern, $hexString, $matches)) {
return [
'hexType' => 2,
'isMatched' => true,
'gateway' => $matches[1],
'card' => $matches[2],
'reader' => $matches[3],
'batteryLevel' => (hexdec($matches[4]) + 200) / 100,
];
}
return ['isMatched' => false];
}
}