服务器列表Ping(Server List Ping,简称SLP)是Minecraft服务器提供的一项网络接口,客户端通过常规端口查询服务器的MOTD、在线玩家数、最大玩家数以及服务器版本。SLP使用与游戏相同的协议,因此与其他查询方式不同,它默认始终开启。原版客户端就是用这个接口来显示多人游戏服务器列表。1.7版本时SLP协议做了不向后兼容的改动,不过现在的服务器仍然同时支持新老协议。
当前版本(1.7+)
这一版本使用常规的客户端-服务器协议。关于一般数据包格式,请参见协议文档。
握手(Handshake)
客户端先发送一个握手包,将状态设为1。
| 数据包ID | 字段名 | 字段类型 | 说明 |
|---|---|---|---|
| 0x00 | 协议版本 | VarInt | 服务器协议版本号。客户端打算用来连接服务器的版本(实际对ping不重要)。如果客户端通过ping来确定该用哪个版本,按约定填-1。 |
| 服务器地址 | String | 主机名或IP,例如 localhost 或 127.0.0.1 | |
| 服务器端口 | Unsigned Short | 默认 25565 | |
| 下一状态 | VarInt | 应填 1,代表状态(status) |
请求(Request)
客户端紧接着发送一个请求包,这个包没有字段。
| 数据包ID | 字段名 | 字段类型 | 说明 |
|---|---|---|---|
| 0x00 | 无字段 |
响应(Response)
服务器应返回一个响应包。注意原版服务器会等待后续的Ping包30秒才超时并发送响应。
| 数据包ID | 字段名 | 字段类型 | 说明 |
|---|---|---|---|
| 0x00 | JSON响应 | String | 见下文 |
JSON响应的格式如下:
{
"version": {
"name": "1.8.7",
"protocol": 47
},
"players": {
"max": 100,
"online": 5,
"sample": [
{"name": "thinkofdeath", "id": "4566e69f-c907-48ee-8d71-d7ba5aa00d20"}
]
},
"description": {
"text": "Hello world"
},
"favicon": "data:image/png;base64,<data>"
}
description是一个聊天组件对象。原版服务器只能提供文本,其中嵌入 § 符号开头的颜色代码。favicon字段可选。sample字段必须存在,但可以为空数组。favicon应为 PNG 图片进行 Base64 编码,并在前面加上data:image/png;base64,。
收到响应包后,客户端可以选择发送下一个包来测延迟,或者如果只需要以上信息,直接断开连接。如果客户端收到格式不正确的响应,会尝试向后兼容的旧版Ping(legacy ping)。
Ping
如果继续,客户端发送一个Ping包,里面包含一个不重要的载荷。
| 数据包ID | 字段名 | 字段类型 | 说明 |
|---|---|---|---|
| 0x01 | 载荷 | Long | 可以是任意数字。原版客户端使用系统相关的时间值(毫秒)。 |
Pong
服务器收到Ping后会回应一个Pong包,然后关闭连接。
| 数据包ID | 字段名 | 字段类型 | 说明 |
|---|---|---|---|
| 0x01 | 载荷 | Long | 应与客户端发送的一致 |
示例
C#、Java、Python、Python3、PHP 等语言的示例代码可在原文档找到。
1.6 版本
1.6使用了一种与Netty重写之前兼容的协议。现代服务器通过起始字节 FE(而非通常的 00)来识别这个协议。
客户端到服务器
客户端连接到服务器标准端口后,不用进行身份验证和登录,而是发送以下数据(十六进制表示):
FE— 服务器列表Ping的数据包标识符01— 服务器列表Ping的载荷(固定为1)FA— 插件消息的数据包标识符00 0B— 后面字符串的长度(固定为11,用short表示)00 4D 00 43 00 7C 00 50 00 69 00 6E 00 67 00 48 00 6F 00 73 00 74— 字符串MC|PingHost的UTF-16BE编码XX XX— 剩余数据的长度(short),计算公式为7 + len(hostname),其中len(hostname)是主机名UTF-16BE编码的字节数XX— 协议版本,例如最后版本的4a(74)XX XX— 后面字符串的字符数(short)...— 客户端正在连接的主机名,UTF-16BE编码XX XX XX XX— 客户端正在连接的端口(int)
所有数据类型均为大端序。
数据包示例(十六进制):
0000000: fe01 fa00 0b00 4d00 4300 7c00 5000 6900 ......M.C.|.P.i.
0000010: 6e00 6700 4800 6f00 7300 7400 1949 0009 n.g.H.o.s.t..I..
0000020: 006c 006f 0063 0061 006c 0068 006f 0073 .l.o.c.a.l.h.o.s
0000030: 0074 0000 63dd .t..c.
服务器到客户端
服务器用一个0xFF踢人包回复。包以单字节标识符 ff 开始,接着是一个两字节的大端short,表示后面字符串的字符数。实际上可以忽略这个长度,因为服务器发送响应后会关闭连接。
前3个字节之后,数据包是一个UTF-16BE字符串,以两个字符开头:§1,接着是空字符(\0)。实际传输中为 00 a7 00 31 00 00。
剩余部分是用空字符(00 00)分隔的字段:
- 协议版本(例如74)
- Minecraft服务器版本(例如1.8.7)
- 服务器MOTD(例如A Minecraft Server)
- 当前玩家数
- 最大玩家数
整个包看起来大致如下:
0000000: ff00 2300 a700 3100 0000 3400 3700 0000 ....§.1...4.7...
0000010: 3100 2e00 3400 2e00 3200 0000 4100 2000 1...4...2...A. .
0000020: 4d00 6900 6e00 6500 6300 7200 6100 6600 M.i.n.e.c.r.a.f.
0000030: 7400 2000 5300 6500 7200 7600 6500 7200 t. .S.e.r.v.e.r.
0000040: 0000 3000 0000 3200 30 ..0...2.0
注意:当使用此协议与1.7.x及更高版本的服务器通信时,响应中的第一个字段(协议版本)总是127,这不是真实的协议号,所以旧客户端会认为该服务器不兼容。
示例
Ruby、PHP等语言的示例代码可参考原文档。
1.4 至 1.5 版本
在1.6之前,客户端到服务器的操作更简单,只发送 FE 01,没有任何后续数据。
示例
PHP、Java、C# 等语言的示例可参考原文档。
Beta 1.8 至 1.3 版本
在1.4之前,客户端只发送 FE。
服务器的响应也只包含3个字段,用 § 分隔:
- 服务器MOTD(例如A Minecraft Server)
- 当前玩家数
- 最大玩家数
整个包看起来类似这样:
0000000: ff00 1700 4100 2000 4d00 6900 6e00 6500 ....A. .M.i.n.e.
0000010: 6300 7200 6100 6600 7400 2000 5300 6500 c.r.a.f.t. .S.e.
0000020: 7200 7600 6500 7200 a700 3000 a700 3100 r.v.e.r.§.0.§.1.
0000030: 30 0
评论 (0)
暂无评论,快来发表第一条评论吧!
发表评论
请先登录后再发表评论
去登录