我正在尝试编写一个 PHP TCP 客户端来连接到 Unreal Engine 5 RCON 服务器。我正在使用 GitHub 上的现有 C# 项目作为参考,但在准备要发送的数据包时遇到了困难。 GitHub 项目准备一个
byte
数组,然后将其发送到服务器。我尝试用 PHP 重写该函数,但不确定是否正确。但更大的问题是 socket_write()
socket_send()
和 fwrite()
都想要一个 string
而我现在有一个 array
。我相信我可以使用 pack()
将数组格式化为字符串来表示字节,但我不确定如何操作。
这是来自 https://github.com/Sp1rit/ArkRcon/blob/master/Rcon/RconPacket.cs 的 C# 函数 所以这显示了我需要发送的内容。
public static implicit operator byte[](RconPacket packet)
{
byte[] buffer = new byte[packet.Size + 4];
packet.Size.ToLittleEndian().CopyTo(buffer, 0);
packet.Id.ToLittleEndian().CopyTo(buffer, 4);
((int)packet.Type).ToLittleEndian().CopyTo(buffer, 8);
Encoding.ASCII.GetBytes(packet.Body).CopyTo(buffer, 12);
return buffer;
}
这是我尝试转换它的方法(参见下面的
ConvertToArray()
)。我确实使用了 __invoke
但因为还有一个反向功能,它不会让我使用 __invoke
两次。我提供了整个课程,以便您可以看到完整的图片,并且可以看到一些注释代码,其中我尝试了不同的操作。
class RconPacket
{
private static int $idCounter = 1;
public $Id;
public int $Type;
public $Body;
public function GetSize()
{
return (!empty($Body) ? strlen($Body) + 10 : 0);
}
public function __construct($type, $body)
{
$this->Id = RconPacket::$idCounter++;
$this->Type = $type;
$this->Body = $body;
}
public function ConvertToArray(): array
{
$buffer = array(); //array_fill(0, $this->GetSize() + 4, 0);
$buffer[] = pack('V', $this->GetSize() + 4); //->copy($buffer, 0);
$buffer[] = pack('V', $this->Id); //->copy($buffer, 4);
$buffer[] = pack('V', (int)$this->Type); //->copy($buffer, 8);
$buffer = array_merge($buffer, array_map(fn($c) => ord($c), str_split($this->Body)));
//$buffer[] = str_split($this->Body)->map(fn($c, $i) => ord($c)); //->copy($buffer, 12);
return $buffer;
}
public static function ConvertToRconPacket(string $data): RconPacket
{
$size = unpack('V', $data)[1];
$id = unpack('V', $data, 4)[1];
$type = unpack('V', $data, 8)[1];
$body = substr($data, 12, $size - 10);
return new RconPacket($id, $type, $body);
}
}
我尝试使用
pack("a", $buffer);
将数组转换为字符串,但是 pack()
还需要 string
基础知识:PHP中的
string
实际上是一个二进制数组(例如$str[3]
是第4个字节),所以你不必使用PHP数组,你可以直接使用pack
打包的字符串功能。
$data = pack('V3a*',
$this->GetSize(),
$this->Id,
(int)$this->Type,
$this->Body);
fwrite($fp, $data);