注意:本页上的内容适用于 Clanforge。如果使用 Multiplay Hosting,请参阅 Multiplay Hosting 文档

服务器查询协议

通过服务器查询协议 (SQP),客户端可以使用 UDP/IP 数据包来检索关于运行中游戏服务器的信息。

客户端通过向服务器发送 ChallengeRequest 来发起查询。服务器通过发送包含 ChallengeIdChallengeResponse 来进行响应。收到 ChallengeResponse 后,客户端可以继续查询服务器来获取信息。

以下各节介绍了 SQP 的技术规范,其中包括数据类型请求类型包格式

SQP 支持的游戏服务器状态信息包括:

  • 服务器名称:游戏服务器的名称。
  • 版本 ID:游戏服务器所运行游戏镜像的标识符。
  • 当前玩家数量:当前已连接的玩家数量。
  • 最大玩家数量:可以加入游戏服务器的最大玩家数量。
  • IP 地址:游戏服务器所在机器的 IP 地址。
  • 端口:游戏服务器的端口,供客户端连接到主机上的特定游戏服务器。
  • 游戏类型:游戏服务器所运行的游戏。
  • 地图:游戏服务器上当前加载的游戏地图。

注意:SQP 与 Clanforge 游戏服务器监控进程协作,以确保游戏服务器报告的信息与 Clanforge 数据库中的信息一致。

要求

在实现 SQP 作为游戏服务器查询协议之前,您必须在游戏客户端一侧使用所有游戏服务器信息填充 ServerInfoData 对象。这样可以确保游戏服务器报告正确的信息。

参考实现

请参阅 go-svrquery中的一个 SQP 示例实现。go-svrquery 是一个 Golang 客户端,用于通过各种查询协议(包括 SQP)与游戏服务器通信。

数据类型

所有服务器查询都包含五种基本数据类型,这些数据都打包在一个数据流中。下表描述了每种数据类型。所有这些类型都是大端字节序。

Name描述
byte8 位字符或无符号整数。
ushort16 位无符号整数。
uint32 位无符号整数。
ulong64 位无符号整数。
string可变长度的字节字段,采用 UTF-8 编码并以一个包含字符串长度的字节为前缀。字符串长度限制为 255 字节。

请求类型

客户端可以向服务器发出五种类型的请求。下表说明了客户端针对每种请求类型预期收到的服务器响应。

请求响应
ChallengeRequest服务器会返回一个挑战码,供客户端在查询请求响应中使用。
带有 ServerInfo 数据块的 QueryRequest服务器会返回关于服务器的基本信息,例如当前玩家数量、最大玩家数量、游戏类型和版本 ID。

数据包类型

下表列出了 SQP 数据包的各个不同类型。

数据包类型字节值
ChallengeRequest0
ChallengeResponse0
QueryRequest1
QueryResponse1

标头

无论是请求还是响应,所有 SQP 数据包都包含一个带有以下数据的标头。

Data类型注释
类型byte包含数据包类型。请参阅数据包类型
ChallengeTokenuintChallengeToken 包含挑战码。QueryRequestQueryResponse 数据包类型需要挑战码。请参阅挑战码
有效负载 包含数据包的正文(如果数据包具有正文的话)

挑战码

SQP 使用挑战码(随机生成的 32 位整数)来确保发出查询请求的客户端与收到挑战码的客户端是一致的。

当客户端首次向服务器发送请求时,服务器会随机选择挑战码并将其包含在数据包标头中。然后,客户端必须在所有后续请求的标头中包含相同的挑战码。

挑战数据包

客户端可以使用挑战数据包来检索用于后续请求的可用挑战码。

> 注意:挑战数据包只有一个标头,而没有有效负载。

请求格式

Data注释
标头请参阅标头

以下代码片段提供了一个 ChallengeRequest 数据包示例:

[0x00000000] 0x00 '\0' unsigned char
[0x00000001] 0x00 '\0' unsigned char
[0x00000002] 0x00 '\0' unsigned char
[0x00000003] 0x00 '\0' unsigned char
[0x00000004] 0x00 '\0' unsigned char

响应格式

Data注释
标头请参阅标头

以下代码片段提供了一个 ChallengeResponse 数据包示例:

[0x00000000] 0x00 '\0' unsigned char
[0x00000001] 0x80 '€' unsigned char
[0x00000002] 0x90 '•' unsigned char
[0x00000003] 0x23 '#' unsigned char
[0x00000004] 0x48 'H' unsigned char

查询数据包

客户端可以发送查询数据包来检索关于服务器的信息。Clanforge 只需要游戏服务器使用 ServerInfo 数据块来响应查询。您可以使用其他请求类型,但对于 Clanforge 而言并不是必需的。

数据块类型

客户端可以通过查询数据包来请求四种不同类型的数据块。不过,本文档只介绍了 ServerInfo 数据块类型,因为 Clanforge 仅支持该数据块类型。

每个数据块类型的字节值表示请求客户端期望收到的响应数据块。收到查询数据包时,服务器会检查请求中的 RequestedChunks 字段并使用数据块类型的字节值执行按位 AND 运算。如果该运算的结果大于零,则服务器便知道已请求了某个数据块类型。

例如,如果 RequestedChunks&1 > 0,服务器会在响应时返回 ServerInfo 数据块。请参阅下面的注意事项。

> 注意:尽管 SQP 协议中提供了四种数据块类型,但是 Clanforge 仅支持 ServerInfo 数据块类型。

RequestedChunk 示例含义检查
00000001ServerInfoRequestedChunks & 0x01 > 0
00000010保留RequestedChunks & 0x02 > 0
00000100保留RequestedChunks & 0x04 > 0
00000010保留RequestedChunks & 0x08 > 0

注意RequestedChunks 可以同时请求多个数据块,因此您的实现必须能够对 RequestedChunks 值执行正确的按位检查。

请求格式

所有查询请求都采用相同的请求格式。

注意:Clanforge Hosting 只需要服务器响应 ServerInfo 请求。因此,这里忽略了所有其他请求类型。

Data类型注释
标头 请参阅标头
版本ushort包含要使用的 SQP 版本。
RequestedChunksbyte包含所请求的 ChunkTypes。请参阅数据块类型

以下代码片段提供了一个 QueryRequest 数据包示例:

[0x00000000] 0x01 '\x1' unsigned char
[0x00000001] 0x80 '€' unsigned char
[0x00000002] 0x31 '1' unsigned char
[0x00000003] 0xbe '¾' unsigned char
[0x00000004] 0x18 '\x18' unsigned char
[0x00000005] 0x00 '\0' unsigned char
[0x00000006] 0x01 '\x1' unsigned char
[0x00000007] 0x01 '\x1' unsigned char

响应格式

所有数据块类型的前四个字段(VersionCurrentPacketLastPacketPacketLength)均遵循相同的标准响应格式。数据包 PacketLength 字段之后的信息因请求类型而异。

标准响应格式

下表列出了对于所有数据块类型都相同的响应部分。

Data类型注释
标头 请参阅标头
版本ushort包含要使用的 SQP 版本。
CurrentPacketbyte不支持。该值应该始终为 0。
LastPacketbyte不支持。该值应该始终为 0。
PacketLengthushort包含数据包在此点之后的长度。

ServerInfo 响应格式

Data类型注释
对于在不同数据块类型之间保持不变的字段,请参阅标准响应格式
ChunkLengthuint包含 ServerInfo 数据块在此点之后的长度。
CurrentPlayersushort包含服务器上的玩家数量。
MaxPlayersushort包含服务器支持的最大玩家数量。
ServerNamestring包含服务器的名称。
GameTypestring包含服务器上的游戏。
BuildIdstring包含服务器的版本编号或版本 ID。
Mapstring包含服务器当前加载的地图。
Portushort包含服务器所开放的游戏端口。

以下代码片段提供了一个 QueryResponse 数据包示例:

[0x00000000] 0x01 '\x1' unsigned char
[0x00000001] 0xc0 'À' unsigned char
[0x00000002] 0x7a 'z' unsigned char
[0x00000003] 0x6c 'l' unsigned char
[0x00000004] 0x3d '=' unsigned char
[0x00000005] 0x00 '\0' unsigned char
[0x00000006] 0x01 '\x1' unsigned char
[0x00000007] 0x00 '\0' unsigned char
[0x00000008] 0x00 '\0' unsigned char
[0x00000009] 0x00 '\0' unsigned char
[0x0000000a] 0x5b '[' unsigned char
[0x0000000b] 0x00 '\0' unsigned char
[0x0000000c] 0x00 '\0' unsigned char
[0x0000000d] 0x00 '\0' unsigned char
[0x0000000e] 0x57 'W' unsigned char
[0x0000000f] 0x00 '\0' unsigned char
[0x00000010] 0x00 '\0' unsigned char
[0x00000011] 0x00 '\0' unsigned char
[0x00000012] 0x10 '\x10' unsigned char
[0x00000013] 0x14 '\x14' unsigned char
[0x00000014] 0x55 'U' unsigned char
[0x00000015] 0x45 'E' unsigned char
[0x00000016] 0x34 '4' unsigned char
[0x00000017] 0x20 ' ' unsigned char
[0x00000018] 0x44 'D' unsigned char
[0x00000019] 0x65 'e' unsigned char
[0x0000001a] 0x64 'd' unsigned char
[0x0000001b] 0x69 'i' unsigned char
[0x0000001c] 0x63 'c' unsigned char
[0x0000001d] 0x61 'a' unsigned char
[0x0000001e] 0x74 't' unsigned char
[0x0000001f] 0x65 'e' unsigned char
[0x00000020] 0x64 'd' unsigned char
[0x00000021] 0x20 ' ' unsigned char
[0x00000022] 0x53 'S' unsigned char
[0x00000023] 0x65 'e' unsigned char
[0x00000024] 0x72 'r' unsigned char
[0x00000025] 0x76 'v' unsigned char
[0x00000026] 0x65 'e' unsigned char
[0x00000027] 0x72 'r' unsigned char
[0x00000028] 0x2e '.' unsigned char
[0x00000029] 0x2f '/' unsigned char
[0x0000002a] 0x53 'S' unsigned char
[0x0000002b] 0x63 'c' unsigned char
[0x0000002c] 0x72 'r' unsigned char
[0x0000002d] 0x69 'i' unsigned char
[0x0000002e] 0x70 'p' unsigned char
[0x0000002f] 0x74 't' unsigned char
[0x00000030] 0x2f '/' unsigned char
[0x00000031] 0x53 'S' unsigned char
[0x00000032] 0x68 'h' unsigned char
[0x00000033] 0x6f 'o' unsigned char
[0x00000034] 0x6f 'o' unsigned char
[0x00000035] 0x74 't' unsigned char
[0x00000036] 0x65 'e' unsigned char
[0x00000037] 0x72 'r' unsigned char
[0x00000038] 0x47 'G' unsigned char
[0x00000039] 0x61 'a' unsigned char
[0x0000003a] 0x6d 'm' unsigned char
[0x0000003b] 0x65 'e' unsigned char
[0x0000003c] 0x2e '.' unsigned char
[0x0000003d] 0x53 'S' unsigned char
[0x0000003e] 0x68 'h' unsigned char
[0x0000003f] 0x6f 'o' unsigned char
[0x00000040] 0x6f 'o' unsigned char
[0x00000041] 0x74 't' unsigned char
[0x00000042] 0x65 'e' unsigned char
[0x00000043] 0x72 'r' unsigned char
[0x00000044] 0x47 'G' unsigned char
[0x00000045] 0x61 'a' unsigned char
[0x00000046] 0x6d 'm' unsigned char
[0x00000047] 0x65 'e' unsigned char
[0x00000048] 0x5f '_' unsigned char
[0x00000049] 0x54 'T' unsigned char
[0x0000004a] 0x65 'e' unsigned char
[0x0000004b] 0x61 'a' unsigned char
[0x0000004c] 0x6d 'm' unsigned char
[0x0000004d] 0x44 'D' unsigned char
[0x0000004e] 0x65 'e' unsigned char
[0x0000004f] 0x61 'a' unsigned char
[0x00000050] 0x74 't' unsigned char
[0x00000051] 0x68 'h' unsigned char
[0x00000052] 0x4d 'M' unsigned char
[0x00000053] 0x61 'a' unsigned char
[0x00000054] 0x74 't' unsigned char
[0x00000055] 0x63 'c' unsigned char
[0x00000056] 0x68 'h' unsigned char
[0x00000057] 0x03 '\x3' unsigned char
[0x00000058] 0x30 '0' unsigned char
[0x00000059] 0x30 '0' unsigned char
[0x0000005a] 0x31 '1' unsigned char
[0x0000005b] 0x08 '\b' unsigned char
[0x0000005c] 0x48 'H' unsigned char
[0x0000005d] 0x69 'i' unsigned char
[0x0000005e] 0x67 'g' unsigned char
[0x0000005f] 0x68 'h' unsigned char
[0x00000060] 0x72 'r' unsigned char
[0x00000061] 0x69 'i' unsigned char
[0x00000062] 0x73 's' unsigned char
[0x00000063] 0x65 'e' unsigned char
[0x00000064] 0x1e '\x1e' unsigned char
[0x00000065] 0x61 'a' unsigned char