RakNet¶
RakNet是一套跨平台、开源的C++游戏网络引擎,最初由Jenkins Software开发,后移交至Facebook Archive进行维护。Minecraft基岩版将RakNet(RakNet)用作面向外部服务器连接的主要传输层协议。
概述¶
RakNet基于UDP,在其上提供可靠性保证、数据包排序、分片重组和连接管理等功能,使游戏网络通信在低延迟的UDP基础上具有类TCP的可靠性。
基岩版默认使用端口19132(IPv4)和19133(IPv6)进行RakNet通信,端口可按需更改。
RakNet中的未连接消息(如Unconnected Ping与Unconnected Pong)携带一个固定的16字节离线消息标识,通称Magic:
每个RakNet数据包的第一个字节为包类型标识符。
数据类型¶
| 类型 | 大小(字节) | 范围 | 说明 |
|---|---|---|---|
u8(byte) | 1 | 0–255 | 单字节无符号整数 |
i16(short) | 2 | −32768–32767 | 有符号16位整数 |
u16(unsigned short) | 2 | 0–65535 | 无符号16位整数 |
u24(unsigned int24) | 3 | 0–2²⁴−1 | 无符号24位整数 |
i64(long) | 8 | −2⁶³–2⁶³−1 | 有符号64位整数 |
bool(boolean) | 1 | 0–1 | 0为false,1为true |
String | 不定 | — | 以大端序u16前缀表示长度,后跟字节序列 |
Guid | 8 | — | 以i64存储的全局唯一标识符 |
Socket Address | 7 | — | 1字节IP版本(4/6),4字节IP地址,2字节端口 |
Magic | 16 | — | 常量字节序列0x00ffff00fefefefefdfdfdfd12345678 |
MOTD格式¶
服务器在Unconnected Pong中向客户端广播其MOTD。MOTD是以分号;分隔的字符串,格式如下:
版本标识字段取值为MCPE(基岩版)或MCEE(教育版)。游戏模式和游戏模式数字字段目前不被原版客户端使用。
示例:
连接流程¶
RakNet连接的建立分为握手阶段和连接阶段。握手阶段用于发现服务端并协商MTU大小;连接阶段在握手完成后正式建立可靠通道。
握手阶段¶
握手阶段共4个数据包:
Open Connection Request 1(客户端→服务端)
空白填充用于探测网络MTU。客户端以递减的填充大小不断重试,直到服务端回复。
Open Connection Reply 1(服务端→客户端)
Open Connection Request 2(客户端→服务端)
Open Connection Reply 2(服务端→客户端)
自此,RakNet连接建立,后续所有RakNet消息均通过帧集合数据包(Frame Set Packet)传输。
连接阶段¶
连接阶段共3个数据包:
Connection Request(客户端→服务端)
Connection Request Accepted(服务端→客户端)
New Incoming Connection(客户端→服务端)
连接保活¶
连接建立后,双方须周期性交换Connected Ping与Connected Pong以维持连接:
- Connected Ping:
0x00 | 时间戳(u64)(以不可靠方式传输) - Connected Pong:
0x03 | 客户端时间戳(u64)| 服务端时间戳(u64)(以不可靠方式传输)
批量发送
原版客户端通常将New Incoming Connection、Connected Ping以及第一个游戏数据包(Network Settings Request)合并为一批发送。自定义RakNet实现需注意处理此种情况,因为部分服务器可能未针对此模式进行测试。
与基岩版网络协议的关系¶
RakNet只负责传输层,基岩版游戏协议在RakNet连接建立之上运行。RakNet连接完成后,游戏层登录流程随即开始。详见网络协议。
实现¶
| 名称 | 说明 | 语言 |
|---|---|---|
| RakNet(官方) | 跨平台开源C++游戏网络引擎 | C++ |
| bedrock-crustaceans/raknet | Rust实现 | Rust |
| NetrexMC/RakNet | Rust实现 | Rust |
| rust-raknet | Rust实现 | Rust |
| tokio-raknet | 基于tokio异步生态的Rust实现 | Rust |
| transport-raknet | Java实现 | Java |
| RakLib | PHP服务端实现 | PHP |
| go-raknet | Go实现 | Go |
| raknet-python | Python绑定 | Python |
| JSPrismarine/raknet | JavaScript/TypeScript实现 | JavaScript/TypeScript |