You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何正确查询服务器信息?含游戏服务器玩家数查询实现代码

查询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

火山引擎 最新活动