服务器查询

From Valve Developer Community
< Zh
Jump to navigation Jump to search
English (en)Français (fr)Русский (ru)中文 (zh)Translate (Translate)

你可以通过 UDP/IP 数据包向正在运行的游戏服务器查询信息。本文档描述了访问这些数据所需的数据包格式和协议。

数据类型

所有服务器查询都由五种基础数据类型组合成数据流。所有类型均为小端序,这也是大多数语言在 x86 CPU 上的默认字节序。Java 用户应使用 ByteBuffer 进行转换。

名称 描述
byte 8 位字符或无符号整数
short 16 位有符号整数
long 32 位有符号整数
float 32 位浮点数
long long 64 位无符号整数
string 可变长度字节字段,使用 UTF-8 编码,以 0x00 结尾


协议

Steam 使用的数据包大小最大为 1400 字节 + IP/UDP 头。如果请求或响应的数据需要更多数据包承载,那么这些数据包会使用新的 IP/UDP 头部。

2023-07-10:已观察到 Rust 打破了这一规则,会发送最大 IP 大小(64KB)的数据包。

简单响应格式

数据 类型 说明
Header long 始终等于 -1 (0xFFFFFFFF)。表示该响应未被拆分。
Payload

多包响应格式

Goldsource 服务器

数据 类型 说明
Header long 始终等于 -2 (0xFFFFFFFE)。表示该数据包是拆分包。
ID long 服务器为每次响应分配的唯一编号。
Packet number byte 高 4 位表示当前数据包编号(从 0 开始),低 4 位表示数据包总数(2 到 15)。
Payload

Source 服务器

数据 类型 说明
Header long 始终等于 -2 (0xFFFFFFFE)。表示该数据包是拆分包。
ID long 含义与 Goldsource 服务器相同。但是,如果 最高有效位 为 1,则表示响应在拆分发送前已使用 bzip2 压缩。请参考下方的压缩流程。
Total byte 此响应的数据包总数。
Number byte 当前数据包编号,从 0 开始。
Size short (仅 Orange Box 引擎及以上版本。) 发生分包前的最大数据包大小。默认值为 1248 字节 (0x04E0),但服务器管理员可以降低该值。对于较旧的引擎版本,数据包的最大和最小大小不可更改。已知不包含该字段的 AppID:215、17550、17700,以及 protocol = 7 时的 240。
仅在响应的第一个数据包中存在,并且仅当响应被压缩时存在。
数据 类型 说明
Size long 解压后完整响应的大小。
CRC32 sum long 未压缩响应的 CRC32 校验和。

要解压此响应:收集并组装所有收到的数据包 payload,然后将其传入类似 C 语言中的 BZ2_bzBuffToBuffDecompress() 、PHP 中的 bzdecompress()],或 Python 中的bz2.decompress() 等函数。压缩似乎已经在较新的 Source 游戏中逐渐淘汰,但仍存在于约 2006 年时期的引擎中。

Payload

由于 UDP 数据包可能乱序到达或延迟到达,因此每个数据包都应通过其 “ID” 和 “Number” 进行验证!无论请求或响应是否带有此头部,后续都会跟随一个整数 -1 (0xFFFFFFFF) 和用户数据。 因此,通过读取前 4 个字节,即可判断数据是拆分响应 (-2),还是单个数据包响应 (-1)。

注意:已观察到部分游戏在使用拆分包方式时,会错误地在拆分 payload 内嵌套单消息头部。

请求

服务器会响应 5 种查询:

A2S_INFO
服务器的基本信息。
A2S_PLAYER
服务器上每个玩家的详细信息。
A2S_RULES
服务器正在使用的规则。
A2A_PING
Ping 服务器。 (已废弃)
A2S_SERVERQUERY_GETCHALLENGE
返回用于 player 和 rules 查询的 challenge number。 (已废弃)

查询应通过 UDP 数据包发送到服务器的监听端口。

Challenge 机制

服务器可能会立即返回数据。然而,由于该响应比请求更大,这会使服务器容易受到反射放大攻击。 因此,服务器可能会使用 S2C_CHALLENGE ('A' or 0x41) 向客户端返回一个 challenge。在这种情况下,客户端应将 challenge number 附加到请求后重新发送。 这一变更于 2020 年 12 月引入,用于解决反射攻击漏洞,建议所有客户端都支持新协议。更多信息请参见 this post 。

本文档之前的结构曾让人误以为只有 A2S_INFO 消息会以这种方式返回 challenge;然而,如果 challenge 被省略、错误或已过期,任何查询都可能返回 `S2C_CHALLENGE` 响应。

A2S_INFO

获取服务器信息,包括但不限于:服务器名称、当前正在运行的地图,以及玩家数量。

l4d2 server 2.2.1.3 update:一些服务器会发送 challenge number,这会导致 hlsw 无法获取服务器信息;

请求格式

数据 类型 值
Header byte 'T' (0x54)
Payload string "Source Engine Query\0"
Challenge long 4 字节 challenge(有时存在,见下方说明)
FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69   ÿÿÿÿTSource Engi
6E 65 20 51 75 65 72 79 00                        ne Query.

challenge number 示例:

服务器响应:

FF FF FF FF 41 0A 08 5E EA

你需要发送:

FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69 6E 65 20 51 75 65 72 79 00 0A 08 5E EA


注意:未来请求中可能会附加额外数据!不要假设带有额外数据的请求就是伪造数据包!

注意:2021-6-19 13:05:43 变更:当 l4d2 服务器从同一 IP 地址收到某些数据包时,可能会拒绝回复。

注意:已观察到部分较旧游戏会同时回复 GoldSource INFO 数据包和较新的 INFO 数据包。

响应格式

Note.png注意: SiN 1 Multiplayer 和 Rag Doll Kung Fu 都使用此响应协议。
数据 类型 说明
Header byte 始终等于 'I' (0x49)
Protocol byte 服务器使用的协议版本。
Name string 服务器名称。
Map string 服务器当前加载的地图。
Folder string 包含游戏文件的文件夹名称。
Game string 游戏完整名称。
ID short 游戏的 Steam Application ID。
Players byte 服务器上的玩家数量。
Max. Players byte 服务器报告可容纳的最大玩家数。
Bots byte 服务器上的 bot 数量。
Server type byte 表示服务器类型:
  • 'd' 表示 dedicated server
  • 'l' 表示 non-dedicated server
  • 'p' 表示 SourceTV relay (proxy)
Environment byte 表示服务器操作系统:
  • 'l' 表示 Linux
  • 'w' 表示 Windows
  • 'm' 或 'o' 表示 Mac (该代码在 L4D1 之后发生变化)
Visibility byte 表示服务器是否需要密码:
  • 0 表示公开
  • 1 表示私有
VAC byte 表示服务器是否使用 VAC:
  • 0 表示未保护
  • 1 表示受保护
只有当服务器正在运行 The Ship 时,响应中才存在以下字段:
数据 类型 说明
Mode byte 表示游戏模式:
  • 0 表示 Hunt
  • 1 表示 Elimination
  • 2 表示 Duel
  • 3 表示 Deathmatch
  • 4 表示 VIP Team
  • 5 表示 Team Elimination
Witnesses byte 逮捕玩家所需的目击者数量。
Duration byte 玩家被目击后到被逮捕前的时间(秒)。
Version string 服务器安装的游戏版本。
Extra Data Flag (EDF) byte 如果存在,该字段指定后续将包含哪些附加数据字段。
仅当 if ( EDF & 0x80 ) 为真时存在:
数据 类型 说明
Port short 服务器的游戏端口号。
仅当 if ( EDF & 0x10 ) 为真时存在:
数据 类型 说明
SteamID long long 服务器的 SteamID。
仅当 if ( EDF & 0x40 ) 为真时存在:
数据 类型 说明
Port short SourceTV 的 spectator 端口号。
Name string SourceTV spectator server 的名称。
仅当 if ( EDF & 0x20 ) 为真时存在:
数据 类型 说明
Keywords string 根据服务器描述游戏的标签(供未来使用)。
仅当 if ( EDF & 0x01 ) 为真时存在:
数据 类型 说明
GameID long long 服务器的 64 位 GameID。如果该字段存在,则低 24 位中包含更准确的 AppID。早期的 AppID 可能因为被强制存储为 16 位而被截断。
Note.png注意: Rag Doll Kung Fu 服务器总是在 “Server type” 中返回 0。


Counter-Strike: Source 响应示例:

FF FF FF FF 49 02 67 61 6D 65 32 78 73 2E 63 6F    ÿÿÿÿI.game2xs.co
6D 20 43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65    m Counter-Strike
20 53 6F 75 72 63 65 20 23 31 00 64 65 5F 64 75     Source #1.de_du
73 74 00 63 73 74 72 69 6B 65 00 43 6F 75 6E 74    st.cstrike.Count
65 72 2D 53 74 72 69 6B 65 3A 20 53 6F 75 72 63    er-Strike: Sourc
65 00 F0 00 05 10 04 64 6C 00 00 31 2E 30 2E 30    e......dl..1.0.0
2E 32 32 00                                        .22.

The Ship 响应示例:

FF FF FF FF 49 07 53 68 69 70 20 53 65 72 76 65    ÿÿÿÿI.Ship Serve
72 00 62 61 74 61 76 69 65 72 00 73 68 69 70 00    r.batavier.ship.
54 68 65 20 53 68 69 70 00 60 09 01 05 00 6C 77    The Ship.`....lw
00 00 01 03 03 31 2E 30 2E 30 2E 34 00             .....1.0.0.4.

SiN 1 Multiplayer 响应示例:

FF FF FF FF 49 2F 53 65 6E 73 65 6D 61 6E 6E 20    ÿÿÿÿI/Sensemann 
53 69 4E 20 44 4D 00 70 61 72 61 64 6F 78 00 53    SiN DM.paradox.S
69 4E 20 31 00 53 69 4E 20 31 00 1D 05 00 10 00    iN 1.SiN 1......
6C 77 00 00 31 2E 30 2E 30 2E 30 00                lw..1.0.0.0.

Rag Doll Kung Fu 响应示例:

FF FF FF FF 49 FC 54 68 65 20 44 75 64 65 27 73     ÿÿÿÿIüThe Dude's
20 64 6F 6A 6F 00 53 6F 63 63 65 72 00 52 44 4B      dojo.Soccer.RDK
46 53 6F 63 63 65 72 00 52 61 67 44 6F 6C 6C 4B     FSoccer.RagDollK
75 6E 67 46 75 3A 20 53 6F 63 63 65 72 00 EA 03     ungFu: Soccer.ê.
01 04 00 00 77 00 00 32 2E 33 2E 30 2E 30 00        ....w..2.3.0.0.


过时的 GoldSource 响应

GoldSource 服务器会使用与 Source 服务器相同的响应。更旧的服务器和 Steam 之前的服务器仍会使用下面的响应格式。可以通过 AppID 区分 GoldSource 与 Source。

数据 类型 说明
Header byte 始终等于 'm' (0x6D)
Address string 服务器的 IP 地址和端口。
Name string 服务器名称。
Map string 服务器当前加载的地图。
Folder string 包含游戏文件的文件夹名称。
Game string 游戏完整名称。
Players byte 服务器上的玩家数量。
Max. Players byte 服务器报告可容纳的最大玩家数。
Protocol byte 服务器使用的协议版本。
Server type byte 表示服务器类型:
  • 'D' 表示 dedicated server
  • 'L' 表示 non-dedicated server
  • 'P' 表示 a HLTV server
Environment byte 表示服务器操作系统:
  • 'L' 表示 Linux
  • 'W' 表示 Windows
Visibility byte 表示服务器是否需要密码:
  • 0 表示公开
  • 1 表示私有
Mod byte 表示该游戏是否为 mod:
只有当 “Mod” 为 1 时,响应中才存在以下字段:
数据 类型 说明
Link string mod 网站 URL。
Download Link string 下载 mod 的 URL。
NULL byte NULL 字节 (0x00)
Version long 服务器安装的 mod 版本。
Size long mod 占用的空间(字节)。
Type byte 表示 mod 类型:
  • 0 表示同时支持单人 和 多人
  • 1 表示 仅 支持多人
DLL byte 表示 mod 是否使用自己的 DLL:
  • 0 表示使用 Half-Life DLL
  • 1 表示使用自己的 DLL
VAC byte 表示服务器是否使用 VAC:
  • 0 表示未保护
  • 1 表示受保护
Bots byte 服务器上的 bot 数量。
Note.png注意: 如果 slot 数为 255,HLTV 服务器可能会返回一个延迟请求,该请求可能不完整或不正确。


响应示例:

FF FF FF FF 6D 37 37 2E 31 31 31 2E 31 39 34 2E    ÿÿÿÿm77.111.194.
31 31 30 3A 32 37 30 31 35 00 46 52 20 2D 20 56    110:27015.FR - V
65 72 79 47 61 6D 65 73 2E 6E 65 74 20 2D 20 44    eryGames.net - D
65 61 74 6D 61 74 63 68 20 2D 20 6F 6E 6C 79 20    eatmatch - only 
73 75 72 66 5F 73 6B 69 20 2D 20 6E 67 52 00 73    surf_ski - ngR.s
75 72 66 5F 73 6B 69 00 63 73 74 72 69 6B 65 00    urf_ski.cstrike.
43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65 00 0C    Counter-Strike..
12 2F 64 6C 00 01 77 77 77 2E 63 6F 75 6E 74 65    ./dl..www.counte
72 2D 73 74 72 69 6B 65 2E 6E 65 74 00 00 00 01    r-strike.net....
00 00 00 00 9E F7 0A 00 01 01 00                   ....ž÷.....

A2S_PLAYER

此查询用于获取当前服务器上的玩家信息。它需要先执行一步来获取 challenge number。

Note.png注意: SourceTV 不会响应此请求。

请求格式

数据 类型 值
Header byte 'U' (0x55)
Challenge int Challenge number,或 -1 (0xFFFFFFFF) 用于接收 challenge number。

Challenge 响应格式:

数据 类型 值
Header byte 'A' (0x41)
Challenge int Challenge number。

Challenge 请求示例:

FF FF FF FF 55 FF FF FF FF                         ÿÿÿÿUÿÿÿÿ"       

Challenge 响应示例:

FF FF FF FF 41 4B A1 D5 22                         ÿÿÿÿAÿÿÿÿ"       

带收到的 challenge number 的 A2S_PLAYER 请求示例:

FF FF FF FF 55 4B A1 D5 22                         ÿÿÿÿUÿÿÿÿ"       

响应格式

数据 类型 说明
Header byte 始终等于 'D' (0x44)
Players byte 已收集信息的玩家数量。
“Players” 中每个玩家都会有以下数据块:
数据 类型 说明
Index byte 玩家数据块索引,从 0 开始。
Name string 玩家名称。
Score long 玩家得分(通常表示 “frags” 或 “kills”)。
Duration float 玩家连接到服务器的时间(秒)。

The Ship 的额外玩家信息(位于数据包中的基础信息之后):

数据 类型 说明
Deaths long 玩家死亡次数
Money long 玩家金钱
Note.png注意: 当玩家正在尝试连接服务器时,他们会被计入玩家数量。但他们不会出现在玩家信息数据块列表中。
Warning.png警告: CS 服务器默认只返回最大玩家数和服务器运行时间。如果你想恢复包含玩家列表的旧格式,需要在 server.cfg 中将服务器 cvar “host_players_show” 改为 “2”。



响应示例:

FF FF FF FF 44 02 01 5B 44 5D 2D 2D 2D 2D 3E 54    ÿÿÿÿD..[D]---->T
2E 4E 2E 57 3C 2D 2D 2D 2D 00 0E 00 00 00 B4 97    .N.W<----.....´—
00 44 02 4B 69 6C 6C 65 72 20 21 21 21 00 05 00    .D.Killer !!!...
00 00 69 24 D9 43                                  ..i$ÙC

The Ship 响应:

FF FF FF FF 44 13 00 53 68 69 70 6D 61 74 65 31    ▒▒▒▒D..Shipmate1
00 00 00 00 00 00 00 80 BF 01 53 68 69 70 6D 61    .......▒▒.Shipma
74 65 32 00 00 00 00 00 00 00 80 BF 02 53 68 69    te2.......▒▒.Shi
70 6D 61 74 65 33 00 00 00 00 00 00 00 80 BF 03    pmate3.......▒▒.
53 68 69 70 6D 61 74 65 34 00 00 00 00 00 00 00    Shipmate4.......
80 BF 04 53 68 69 70 6D 61 74 65 35 00 00 00 00    ▒▒.Shipmate5....
00 00 00 80 BF 07 28 31 29 4C 61 6E 64 4C 75 62    ...▒▒.(1)LandLub
62 65 72 00 00 00 00 00 D3 8E 68 45 00 00 00 00    ber.....ӎhE....
C4 09 00 00 00 00 00 00 C4 09 00 00 00 00 00 00    ▒.......▒.......
C4 09 00 00 00 00 00 00 C4 09 00 00 00 00 00 00    ▒.......▒.......
C4 09 00 00 00 00 00 00 C4 09 00 00                ▒.......▒...    

A2S_RULES

返回服务器规则,或者以名称/值对形式返回配置变量。此查询需要先执行 challenge 步骤。

包含的 控制台变量 是带有 FCVAR_NOTIFY 标记的变量,以及服务器配置中列出的其他变量。

请求格式

数据 类型 值
Header byte 'V' (0x56)
Challenge long Challenge number,或 -1 (0xFFFFFFFF) 用于接收 challenge number。

Challenge 响应格式:

数据 类型 值
Header byte 'A' (0x41)
Challenge long Challenge number.

Challenge 请求示例:

FF FF FF FF 56 FF FF FF FF                         ÿÿÿÿVÿÿÿÿ"       

Challenge 响应示例:

FF FF FF FF 41 4B A1 D5 22                         ÿÿÿÿVK¡Õ"       
Warning.png警告: 自 CSGO 1.32.3.0 更新(2014 年 2 月 21 日)以来,CS 的 Rules 回复已损坏。更新前,rules 在超过 MTU 时会被截断;更新后,rules 回复完全不会发送。你也可能会在控制台看到类似消息:[NET] Cannot send connectionless packet to xxx.xxx.xxx.xxx '0x45' exceeding MTU (2644)

包含收到的 challenge number 的最终请求:

FF FF FF FF 56 4B A1 D5 22                         ÿÿÿÿVK¡Õ"       

响应格式

Note.png注意: 此查询的响应通常是多包响应。
数据 类型 说明
Header byte 始终等于 'E' (0x45)
Rules short 响应中的规则数量。
“Rules” 中每条规则都会有以下数据块:
数据 类型 说明
Name string 规则名称。
Value string 规则值。

A2A_PING

Ping 服务器以确认其是否存在,也可用于计算到服务器的延迟。

Warning.png警告: 根据 Valve 的说法 (参见 讨论页),Counter-Strike: Source 和 Team Fortress 2 服务器已不再支持 A2A_PING,并且该功能被视为已废弃。

请求格式

数据 类型 值
Header byte 'i' (0x69)
FF FF FF FF 69                                     ÿÿÿÿi           

响应格式

Goldsource 服务器
数据 类型 值
Header byte 'j' (0x6A)
Payload string Null
FF FF FF FF 6A 00                                  ÿÿÿÿj.           
Source 服务器
数据 类型 值
Heading byte 'j' (0x6A)
Payload string '00000000000000.'
FF FF FF FF 6A 30 30 30 30 30 30 30 30 30 30 30    ÿÿÿÿj00000000000
30 30 30 00                                        000.

A2S_SERVERQUERY_GETCHALLENGE

A2S_PLAYER 和 A2S_RULES 查询都需要 challenge number。过去,可以通过 A2S_SERVERQUERY_GETCHALLENGE 请求获取这个数字。在较新的游戏中,该请求已不再有效。现在应改为发送初始 challenge 为 -1 (0xFFFFFFFF) 的 A2S_PLAYER 或 A2S_RULES 查询,以接收可用的 challenge number。

在某些引擎上仍可使用该请求 (已确认的 AppID:17510, 17530, 17740, 17550, 17700) 。格式如下:

请求格式

数据 类型 值
Header byte 'W' (0x57)
FF FF FF FF 57                                     ÿÿÿÿW           

响应格式

数据 类型 说明
Header byte 应等于 'A' (0x41)。
Challenge long 要使用的 challenge number。

响应示例:

FF FF FF FF 41 4B A1 D5 22                         ÿÿÿÿAK¡Õ"       

协议实现库

参见