测试版本为1.20.6,插件服务器,理论上适用于1.7+版本服务器,已知forge服务器在测试延迟时会出现未收到 Server response的情况

开源Minecraft Server Status已在Github发布,项目地址:https://github.com/GoodBoyboy666/Minecraft-Server-Status

数据包结构

在wiki.vg上我们可以看到,Minecraft数据包的格式如下图:

图片

整个数据包格式采用数据包长度+Packet ID+数据的格式。

数据包长度Packet ID均使用VarInt数据类型,具体可以看 varint是啥你真的知道么?

这里的数据包长度仅包含Packet ID+数据的长度,不包含数据包长度自身的长度。

握手

TCP三次握手不再赘述,这里主要讲与Minecraft Server之间的握手

图片

从上图中可以看出HandShake包的大致结构:Packet ID+Protocol Version+Server Address+Server Port+Next state

HandShake包的ID为0x00Protocol Version具体可以参考Protocol version numbersServer AddressServer Port则为服务器地址和端口,Next state为下一步状态,1为获取状态,2为登录。

因此参考wiki后理论上整个完整的HandShake包结构为:

VarInt类型的Pakect Length+Packet ID+VarInt类型的Protocol Version+String类型的Server Address+Unsigned Short类型的Server Port+VarInt类型的Next state

但实际上通过抓包后发现Protocol VersionServer Address仍存在字节,经过测试后发现为Server Address的VarInt类型的长度数值,因此正确完整的HandShake包结构为:

VarInt类型的Pakect Length+Packet ID+VarInt类型的Protocol Version+VarInt类型的Server Address Length+String类型的Server Address+Unsigned Short类型的Server Port+VarInt类型的Next state

受大小端影响,Server Port部分转换为byte内容后顺序可能会受影响,但不影响服务器响应,实测MC客户端以大端排序和模拟客户端以小端排序发送包后均可以得到服务器正确响应。

例如一次抓包得到客户端HandShake十六进制数据为:18 00 fe 05 11 6d 63 2e 67 6f 6f 64 62 6f 79 62 6f 79 2e 74 6f 70 63 dd 01

拆分后可以得到:

18为VarInt类型的整个数据包长度(不包含18)——24字节

00为Packet ID——0x00

fe 05为VarInt类型的Protocol Version——766

11为VarInt类型的Server Address的长度——17字节

6d 63 2e 67 6f 6f 64 62 6f 79 62 6f 79 2e 74 6f 70为Server Address——mc.goodboyboy.top

63 dd为Unsigned Short类型的Server Port——25565(大端排序)

01为VarInt类型的Next state——0x01

获取状态

通过下图可以看到Status Request包的结构:

图片

因此整个完整的Status Request包为:

VarInt类型的Pakect Length+Packet ID

无需带任何数据

通过抓包可以得到01 00

01为整个包长度(不包含01)——1个字节

00为Packet ID,请求服务器状态。

状态响应

从下图可以看出主要的数据载体为JSON

图片

服务器状态响应包结构在wiki上没有很直观展示,只对返回的json进行了展示,经过测试后得出下面结构:

VarInt类型的Pakect Length+Packet ID+VarInt类型的JSON数据长度+JSON数据

将JSON数据解析出来即可得到服务器状态Motd

Ping

在获取完服务器状态后可以直接进行Ping测试,测试精度取决于当前计算机以及实现代码。

从下图中可以看出Ping包的结构:

图片

结构同样是:

VarInt类型的Pakect Length+Packet ID+数据

因为只是进行延迟测试,所以数据具体内容不重要,但不能没有。

抓包数据:09 01 00 00 00 00 00 00 2e 5d

通过抓包发现客户端的Ping包包含了8个字节数据,加上1位Pakect Length与Packet ID,总数据包大小为10字节。

推荐使用客户端格式使用8位任意数据。

在发送Ping包后服务器会返回同样的数据包以做应答

在wireshark上可以看到

1849 → 25565 [PSH, ACK] Seq=28 Ack=13939 Win=263424 Len=10
25565 → 1849 [PSH, ACK] Seq=13939 Ack=38 Win=42496 Len=10

数据Data均为09010000000000002e5d

参考

MineCraft协议——握手篇(讲解+实现)

Protocol version numbers

Server List Ping

Status Response

Clientbound

What does the normal status ping sequence look like?

Protocol

VarInt and VarLong

varint是啥你真的知道么?