文章出处: MineCraft协议-握手篇
与服务器会话的状态
mc客户端与服务器的会话,可能有这么几种状态.
- Handshaking正在握手
- Status 查询服务器状态
- Login正在登入
- Play正在进行游戏
与服务器建立连接后, 总是进入握手状态, 在握手过程中, 可以选择接下来进入Status状态或者Login状态, 登录成功后, 将进入Play状态.
常用的字段及和编码格式
定长整数
定长整数: Byte(一个字节), Sort(两个字节), Int(四个字节), Long(8个字节)和UnsignedByte(一个字节), UnsignedSort(两个字节), UnsignedInt(4个字节), UnsignedLong(8个字节).
均用大端法排列, 即表示高有效位的字节排在前面, 第一位是符号位, 负数用补码
变长整数
变长整数: VarInt, VarLong
VarInt用于编码int类型, 占1~5字节, 每个字节用低7位来编码数字. 最高一位如果位为1, 表示还有下一个字节. 最高位为0时, 表示没有下一字节了. 表示低有效位的字节排在前面, 表示高有效位的字节排在后面。
符号位无需单独处理, 不把符号位看成符号位即可
变长整数也是用大端法
比如:
127 = 0x00 00 00 80 =》 0x80 01
-1 = 0xFF FF FF FF =》 0xFF FF FF FF 0F
Varint表示比较小的整数时很节约字节,对于比较大的整数也能表示。但是对于任何负数, 它始终会占用5个字节
VarLong用于编码long类型,转化方法同理
字符串
字符串由两部分组成, 一个VarInt前缀, 表示字符串按UTF-8编码之后的长度, 接下来是用UTF-8编码的字符串本身
比如:
“FML”按UTF-8编码-》0x46 4D 4C-》长度为三字节, 3按Varint编码:0x03-》完整的字符串:0x03 46 4D 4C
包格式
mc将要发送的数据封装成包(packet)再发送给服务器或客户端
| 域名称 | 域类型 | 注释 |
|---|---|---|
| 长度 | Varint | 包数据的长度 + 包序号的长度 |
| 包序号 | VarInt | |
| 数据 | Byte Array | 依赖于连接状态和包序号, 详见下面的部分 |
包序号(Packet ID), 或者更正确的叫包ID, 表示这个包的类型, 这个包是干什么的, 有哪些字段. 注意. 包可分为发往客户端的包和发往服务器的包两类. 这两类包的id是分开数据, 由字段依次连接而成, 具体包含哪些字段取决于包ID
mc握手和SLP
通过Server List Ping(SLP)可以得到服务器的有关信息(由几哥玩家在线, 服务器的名字版本号, 装了哪些mod)和连接的时延
具体过程如下:
Packet ID | Field Name Field Type | Notes
:- | :- | :- |:-
0x00 | protoco Version | Varint | the vers that the client plans on using to the server(which is not important for the ping). if the client is
pinging to determine what version to use, by convertion -1 shouled be set.
| Server Address | String | homstname or IP, e.g localhost or 127.0.0.1
| Server Port | Unsigned Short | default is 25565
| Next state | Varint | should be 1, for status
例如
1 | 00 |
分行方便阅读
上面那串数字为原始的16进制数, 若要以byte形式发出服务器, 先把上面的16进制数换成10进制形式
包ID = 0, 对应第一行
字段
协议号Varint: 参考文章基于mc 1.12.2 协议号340, 对应第二行D4 02
服务器地址String: 字符串, ip或者域名, 比如127.0.0.1, 对应第三行. 测试用的forge客户端, 实际发送的是”127.0.0.1\0FML\0”, \0表示00, ASCII码空字符, FML显然是forge mod loader的缩写.
端口号UnsignedSort: 默认25565, 对应第四行27 66
下一个状态Varint: 只能是1或者2, 1表示进入Status状态, 2表示进入Login状态, 例子中是02, 要获取服务器信息则应该填01
客户端发Request包
Packet ID | Field Name Field Type | Notes
:- | :- | :- |:-
0x00 | no fields | |
对应的二进制应该是0x100. 第一个字节是包长度, 第二个字节包id, 数据部分没有
服务器回应Response包
Packet ID | Field Name Field Type | Notes
:- | :- | :- |:-
0x00 | JSON Response | String | see blow
一个字段, string, json格式的服务器信息