【问题标题】:Java sending handshake packets to minecraft serverJava 向 minecraft 服务器发送握手包
【发布时间】:2015-08-26 09:34:32
【问题描述】:

我一直在开发一个基本上类似于 Minechat 的 Java 程序(基于文本的应用程序来查看聊天。)我从来没有真正使用过网络太多,所以问题是弄清楚如何正确发送数据包。我目前正处于与服务器创建握手的位置。经过数小时的研究,我想出了以下代码,但它总是遇到“失败!(异常)”消息。对我来说,一切看起来都是正确的,但据我所知,这可能是 100% 错误的。如果有人能指出我在这里做错了什么,我将不胜感激。

作为参考,请随意使用thisthis

public static void main(String[] args) throws IOException {
    host = new InetSocketAddress("162.244.165.111", 48040);
    socket = new Socket();
    System.out.println("Connecting...");
    socket.connect(host, 3000);
    System.out.println("Done!");
    System.out.println("Making streams...");
    output = new DataOutputStream(socket.getOutputStream());
    input = new DataInputStream(socket.getInputStream());
    System.out.println("Done!");
    System.out.println("Attempting handshake... "+host.getAddress().toString().substring(1));
    byte[] msg = ("47;"+host.getAddress().toString().substring(1)+";"+host.getPort()+";2;").getBytes(Charset.forName("UTF-16"));
    output.writeInt(msg.length+Integer.valueOf(0x00));
    output.writeByte(0x00);
    output.write(msg);
    output.flush();
    try {
        if (input.readByte() != 0x02)
            System.out.println("Failed!");
        else
            System.out.println("Done!");
    } catch (EOFException e) {
        System.out.println("Failed! (Exception)");
    }
}

编辑: 更多研究表明我使用 Byte 数组,但这让我对如何表示字符串以及需要使用字符串感到困惑?

【问题讨论】:

    标签: java network-programming minecraft packets


    【解决方案1】:

    查看此页面http://wiki.vg/Protocol 看起来您没有写入足够的数据,也没有按正确的顺序。您还需要使用varint,这是一种特殊类型的整数数据表示。

    此问题的相关链接:


    状态 ping 的工作原理如下:
    C->S : Handshake State=1
    C->S : Request
    S->C : Response
    C->S : Ping
    S->C : Pong
    

    C 是客户端,S 是服务器

    使用 wiki 和提供的代码示例,我修改了您的代码以遵循整个状态请求。

    public static void main(String [] args) throws IOException {
        String address = "162.244.165.111";
        int port = 48040;
    
        InetSocketAddress host = new InetSocketAddress(address, port);
        Socket socket = new Socket();
        System.out.println("Connecting...");
        socket.connect(host, 3000);
        System.out.println("Done!");
        System.out.println("Making streams...");
        DataOutputStream output = new DataOutputStream(socket.getOutputStream());
        DataInputStream input = new DataInputStream(socket.getInputStream());
    
        System.out.println("Done!");
        System.out.println("Attempting handshake... "+host.getAddress().toString());
    
    
        byte [] handshakeMessage = createHandshakeMessage(address, port);
    
        // C->S : Handshake State=1
        // send packet length and packet
        writeVarInt(output, handshakeMessage.length);
        output.write(handshakeMessage);
    
        // C->S : Request
        output.writeByte(0x01); //size is only 1
        output.writeByte(0x00); //packet id for ping
    
    
        // S->C : Response
        int size = readVarInt(input);
        int packetId = readVarInt(input);
    
        if (packetId == -1) {
            throw new IOException("Premature end of stream.");
        }
    
        if (packetId != 0x00) { //we want a status response
            throw new IOException("Invalid packetID");
        }
        int length = readVarInt(input); //length of json string
    
        if (length == -1) {
            throw new IOException("Premature end of stream.");
        }
    
        if (length == 0) {
            throw new IOException("Invalid string length.");
        }
    
        byte[] in = new byte[length];
        input.readFully(in);  //read json string
        String json = new String(in);
    
    
        // C->S : Ping
        long now = System.currentTimeMillis();
        output.writeByte(0x09); //size of packet
        output.writeByte(0x01); //0x01 for ping
        output.writeLong(now); //time!?
    
        // S->C : Pong
        readVarInt(input);
        packetId = readVarInt(input);
        if (packetId == -1) {
            throw new IOException("Premature end of stream.");
        }
    
        if (packetId != 0x01) {
            throw new IOException("Invalid packetID");
        }
        long pingtime = input.readLong(); //read response
    
    
        // print out server info
        System.out.println(json);
    
        System.out.println("Done!");
    }
    
    public static byte [] createHandshakeMessage(String host, int port) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
    
        DataOutputStream handshake = new DataOutputStream(buffer);
        handshake.writeByte(0x00); //packet id for handshake
        writeVarInt(handshake, 4); //protocol version
        writeString(handshake, host, StandardCharsets.UTF_8);
        handshake.writeShort(port); //port
        writeVarInt(handshake, 1); //state (1 for handshake)
    
        return buffer.toByteArray();
    }
    
    public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
        byte [] bytes = string.getBytes(charset);
        writeVarInt(out, bytes.length);
        out.write(bytes);
    }
    
    public static void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
        while (true) {
            if ((paramInt & 0xFFFFFF80) == 0) {
              out.writeByte(paramInt);
              return;
            }
    
            out.writeByte(paramInt & 0x7F | 0x80);
            paramInt >>>= 7;
        }
    }
    
    public static int readVarInt(DataInputStream in) throws IOException {
        int i = 0;
        int j = 0;
        while (true) {
            int k = in.readByte();
            i |= (k & 0x7F) << j++ * 7;
            if (j > 5) throw new RuntimeException("VarInt too big");
            if ((k & 0x80) != 128) break;
        }
        return i;
    }
    

    【讨论】:

    • 感谢非常详细的回答!这非常有用。
    猜你喜欢
    • 2013-03-05
    • 1970-01-01
    • 2012-06-07
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多