Zh:Query

From wiki.vg
Revision as of 14:15, 28 November 2019 by Kaniol (talk | contribs) (Created page with "Query是一个在1.9pre4引入用于查询服务端属性的UDP协议。它注定兼容[http://wiki.unrealadmin.org/UT3_query_protocol UT3(或GameSpot)Query协议] 一个...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Query是一个在1.9pre4引入用于查询服务端属性的UDP协议。它注定兼容UT3(或GameSpot)Query协议

一个稍简单的查询协议的替代方案包含连接到Minecraft主TCP端口并发送一个服务端列表Ping数据包,它将会返回MOTD、玩家的数量以及槽的数量。更多细节请见主协议页面

所有的数据类型都是大字节序的,short除外。

服务端配置

enable-query=true
query.port=<1-65535>

默认的端口是建立在server-port上的。

基础数据包格式

客户端至服务端数据包格式

字段名称 字段类型 注释
Magic short 总是65277(0xFEFD)
Type byte 9代表握手,0代表状态
Session ID int32
Payload 可变 见下

服务端至客户端数据包格式

字段名称 字段类型 注释
Type byte 9代表握手,0代表状态
Session ID int32
Payload 可变 见下

握手

生成Session ID

会话ID(Session ID)用于区分你的请求。接下来的示例使用会话ID = 1(编码为十六进制转储00 00 00 01)。

只有会话ID每一字节的低四位才会被使用,而高四位则不会被Minecraft处理。要将任何4字节的会话ID转换为有效的Minecraft会话ID,只需使用sessionId & 0x0F0F0F0F进行位掩码。

请求

使用空负载发送一个请求。

字段名称 字段类型 示例
Magic short FE FD
Type byte 09
Session ID int32 00 00 00 01
Payload (empty)

转储:

FE FD 09 00 00 00 01

响应

该响应负载会是一个challenge token,编码为空终止字符串。你应该将其转换为int32并存储它。

字段名称 字段类型 示例
Type byte 09
Session ID int32 00 00 00 01
Challenge令牌字符串 空终止字符串 "9513307\0"

在这个示例中,解析字符串"9513307\0"为整型并将他导报为大字节序的int32后,结果应为00 91 29 5B。

转储:

09 00 00 00 01 39 35 31 33 33 30 37 00 | .....9513307.         

challenge令牌过期

引用有关Minecraft查询协议的Dinnerbone的原始文章

注意challenge令牌绑定至你的IP和端口(与[session ID]相反),并持续达30秒。对,你没看错,这取决于;这不是“你的令牌将在将在30秒后过期”,而是“每个令牌都在30秒后过期”。这意味着你完全有可能得到一个令牌并在同一秒内使用它并使它过期了。

另外:

你需要提供你的challenge令牌,否则将不会收到任何回复。如果你提供了一个错误的令牌,那么仍不会收到任何回复。记住,如果你想存储你的challenge令牌并在以后使用,那么你需要在等待回复时设置一些超时,以防在服务器重启后你的令牌不再有效。不可能在没有任何额外请求的情况下区分离线服务器和拒绝你challenge的服务器,所以你需要尝试另一个challenge令牌,如果这也失败了,那么就标记它为不可用。

标准状态

请求

你的负载应该时你的challenge令牌,以int32打包。

字段名称 字段类型 示例
Magic short FE FD
Type byte 00
Session ID int32 00 00 00 01
Challenge令牌 int32 00 91 29 5B

转储:

FE FD 00 00 00 00 01 00 91 29 5B

响应

字段名称 字段类型 示例
Type byte 00
Session ID int32 00 00 00 01
MOTD Null-terminated string "A Minecraft Server\0"
gametype Null-terminated string "SMP\0"
map Null-terminated string "world\0"
numplayers Null-terminated string "2\0"
maxplayers Null-terminated string "20\0"
hostport Little endian short DD 63 ( = 25565)
hostip Null-terminated string "127.0.0.1\0"

转储:

00 00 00 00 01 41 20 4D 69 6E 65 63 72 61 66 74 | .....A Minecraft
20 53 65 72 76 65 72 00 53 4D 50 00 77 6F 72 6C |  Server.SMP.worl
64 00 32 00 32 30 00 DD 63 31 32 37 2E 30 2E 30 | d.2.20.##127.0.0
2E 31 00                                        | .1.

完整状态

本方法没5秒缓存一次。

请求

该请求与基础状态中时一样的,除了负载必须填充至8字节。最后发送0x00 0x00 0x00 0x00。

字段名称 字段类型 示例
Magic short FE FD
Type byte 00
Session ID int32 00 00 00 01
Challenge令牌 int32 00 91 29 5B
Padding 00 00 00 00

转储:

FE FD 00 00 00 00 01 00 91 29 5B 00 00 00 00

响应

该响应分为两个部分。第一部分是一个零终止字符串列表,代表了(key1、value1、key2、value2…)。第二部分是另一个零终止字符串列表,每一项代表一个玩家。

一个解析该负载的简单方法是忽略最前面的11字节,然后使用令牌\x00\x01player_\x00\x00拆分响应。最后面是多余的零字节。

字段名称 字段类型 示例 注释
Type byte 00
Session ID int32 00 00 00 01
Padding 11字节,常量 73 70 6C 69 74 6E 75 6D 00 80 00 无意义
K、V部分 多对零终止字符串 hostname\0A Minecraft Server\0gametype\0SMP\0 ... hostip\0127.0.0.1\0\0 当你读取到0长度的键时终止(退出循环,不再读取值)
Padding 10字节,常量 01 70 6C 61 79 65 72 5F 00 00 无意义
Players部分 多个零终止字符串 "barneygale\0TkTech\0 ... sadimusi\0\0" 当你读取到0长度的玩家名称时终止

转储:

00 00 00 00 01 73 70 6C 69 74 6E 75 6D 00 80 00 | .....splitnum...
68 6F 73 74 6E 61 6D 65 00 41 20 4D 69 6E 65 63 | hostname.A minec
72 61 66 74 20 53 65 72 76 65 72 00 67 61 6D 65 | raft Server.game
74 79 70 65 00 53 4D 50 00 67 61 6D 65 5F 69 64 | type.SMP.game_id
00 4D 49 4E 45 43 52 41 46 54 00 76 65 72 73 69 | .MINECRAFT.versi
6F 6E 00 42 65 74 61 20 31 2E 39 20 50 72 65 72 | on.Beta 1.9 Prer
65 6C 65 61 73 65 20 34 00 70 6C 75 67 69 6E 73 | elease 4.plugins
00 00 6D 61 70 00 77 6F 72 6C 64 00 6E 75 6D 70 | ..map.world.nump
6C 61 79 65 72 73 00 32 00 6D 61 78 70 6C 61 79 | layers.2.maxplay
65 72 73 00 32 30 00 68 6F 73 74 70 6F 72 74 00 | ers.20.hostport.
32 35 35 36 35 00 68 6F 73 74 69 70 00 31 32 37 | 25565.hostip.127
2E 30 2E 30 2E 31 00 00 01 70 6C 61 79 65 72 5F | .0.0.1...player_
00 00 62 61 72 6E 65 79 67 61 6C 65 00 56 69 76 | ..barneygale.Viv
61 6C 61 68 65 6C 76 69 67 00 00                | alahelvig..

K、V部分

示例值 描述
hostname 'A Minecraft Server' 当前服务端的MOTD
game type 'SMP' 硬编码为SMP
game_id 'MINECRAFT' 硬编码为MINECRAFT
version '1.2.5' 服务端版本
plugins 'CraftBukkit on Bukkit 1.2.5-R4.0:

WorldEdit 5.3; CommandBook 2.1'

插件列表,原版服务端不使用,而只是一个空字符串(但仍然是零终止的,见上面的十六进制转储)。

这是由Dinnerbone提议的格式,且当前用于Bukkit:
[SERVER_MOD_NAME[: PLUGIN_NAME(; PLUGIN_NAME...)]]

map 'world' 当前地图的名称
numplayers '1' 在线玩家的数量。该字符串可以解析至数字。
max players '20' 服务端的最大玩家数量。该字符串可以解析至数字。
host port '25565' 服务端端口。该字符串可以解析至数字。
host ip '127.0.0.1' 服务端监听/联系的IP地址。

示例实现