如何正确查询服务器信息?含游戏服务器玩家数查询实现代码
查询Source引擎游戏服务器玩家数量的Java实现
嘿,我看你正在用Java尝试查询游戏服务器的玩家数量,刚好这个场景是针对Valve Source引擎的服务器(比如CS:GO、TF2这类,端口27017是默认查询端口),我来帮你补全代码并拆解关键逻辑——这类服务器用的是Valve的A2S查询协议,咱们一步步来搞定。
首先,先补全你的代码,实现最基础的玩家数量查询(从服务器基本信息里获取):
import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketTimeoutException; public class GameServerQuery { public static void main(String[] args) { String hostname = "85.190.155.70"; int port = 27017; // A2S_INFO 查询请求包(符合Valve协议格式) byte[] requestPacket = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 'T', 'S', 'o', 'u', 'r', 'c', 'e', ' ', 'Q', 'u', 'e', 'r', 'y', '\0' }; try { InetAddress address = InetAddress.getByName(hostname); DatagramSocket socket = new DatagramSocket(); socket.setSoTimeout(3000); // 设置3秒超时,避免无限等待 // 发送查询请求 DatagramPacket sendPacket = new DatagramPacket(requestPacket, requestPacket.length, address, port); socket.send(sendPacket); // 接收服务器响应 byte[] buffer = new byte[1024]; DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length); socket.receive(receivePacket); // 解析响应获取玩家数量 // A2S_INFO响应格式:前4字节是0xFFFFFFFF,然后是'I',接着是字符串和字节数据 int offset = 5; // 跳过前5字节(4个FF + 'I') // 跳过服务器名称、地图名、游戏目录、游戏描述这些字符串 while (buffer[offset] != 0) offset++; offset++; while (buffer[offset] != 0) offset++; offset++; while (buffer[offset] != 0) offset++; offset++; while (buffer[offset] != 0) offset++; offset++; // 现在offset指向玩家数字节 int playerCount = buffer[offset] & 0xFF; // 转成无符号整数 int maxPlayers = buffer[offset + 1] & 0xFF; System.out.println("当前在线玩家数: " + playerCount); System.out.println("服务器最大玩家数: " + maxPlayers); socket.close(); } catch (SocketTimeoutException e) { System.err.println("请求超时,服务器可能未响应或不可达"); } catch (IOException e) { e.printStackTrace(); } } }
关键逻辑说明:
- 协议格式:Source服务器的查询需要特定的UDP包格式,开头的4个
0xFF是协议标识,后面的字符串是握手内容 - 响应解析:A2S_INFO的响应是二进制格式,里面包含服务器名称、地图、玩家数等信息,我们需要跳过前面的字符串字段,找到存储玩家数的字节位置
- 超时处理:设置Socket超时很重要,避免因为UDP丢包或者服务器无响应导致程序卡住
如果你需要更精确的玩家统计(比如排除AI机器人),可以改用A2S_PLAYER查询协议,发送对应的请求包后,解析返回的每个玩家条目,统计非bot的数量:
// A2S_PLAYER 查询请求包(需要先获取挑战值,这里简化用0) byte[] playerRequest = { (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 'U', (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00 };
然后解析响应时,每个玩家条目包含是否是bot的标识,你可以遍历统计真实玩家数量。
注意事项:
- 部分服务器可能开启了查询限制,需要确保你的IP没有被服务器拉黑
- UDP是无连接协议,可能需要重试几次请求来确保收到响应
- 不同的游戏服务器可能有细微的协议差异,比如有些服务器需要先发送挑战请求再发送查询包
内容的提问来源于stack exchange,提问作者xFish




