C# 使用 tcp/ip 从 Minecraft 服务器获取数据包

Posted

技术标签:

【中文标题】C# 使用 tcp/ip 从 Minecraft 服务器获取数据包【英文标题】:C# Getting a packet from a Minecraft server using tcp/ip 【发布时间】:2022-01-10 07:00:31 【问题描述】:

我的主要目标是将 C# 客户端连接到 Minecraft 服务器,但我在获取服务器发送的数据包内容时遇到了一些麻烦。根据this page,Minecraft 中的数据包应该匹配特定的格式。 (Format of a packet)

另外,根据this,字符串的前缀是长度。

这是the packet,我正在尝试获取。

知道这些信息,这是我的代码:

  //S->C : Login Success
  int packet_Length = ReadVarInt(stream);
  int packet_Id = ReadVarInt(stream);


  int uuid_length = ReadVarInt(stream);
  string uuid = ReadString(stream, 16);

  int name_length = ReadVarInt(stream);
  string name = ReadString(stream, 16);


public static int ReadVarInt(Stream stream)
    
        int value = 0;
        int length = 0;
        int currentByte;

        while (true)
        
            currentByte = stream.ReadByte();
            value |= (currentByte & 0x7F) << (length++ * 7);
            if (length > 5) throw new IOException("VarInt too big");
            if ((currentByte & 0x80) != 0x80) break;
        
        return value;
    

 public static string ReadString(Stream stream, int length)
    
        byte[] data = new byte[length];
        stream.Read(data);
        return Encoding.UTF8.GetString(data);
    

结果:

packet_Length : 3
packet_Id : 3
uuid : ↓☻►v9Q?►1??w??
name : 9♠mc_bot

问题是数据包ID应该是1,uuid是常规字符串,name只有“mc_bot ”作为值。我准确地说,必须在完美工作之前完成的部分(我认为)因为客户端在获得 Login Success 数据包后加入服务器,但我无法正确获取任何数据。

谢谢!

【问题讨论】:

一个 UUID 是 32 个字符长度或 36 个 - 好的,这很酷!如果你修复它,你可以自我回答分享你如何修复它:) 我误删了我之前的帖子...感谢您让我走上正确的道路! 没问题,很高兴!还有,没关系,评论不是很重要 【参考方案1】:

所以,在一些帮助下,我终于发现了我的流程出了什么问题。我想指出,老实说,通过正确阅读文档可以轻松避免此类错误,而我没有这样做...

这是我的最终代码

                int packet_Length = ReadVarInt(stream);
                int packet_Id = ReadVarInt(stream);

                Console.WriteLine($"packet_Length : packet_Length");
                Console.WriteLine($"packet_Id : packet_Id");

                //Enables compression. If compression is enabled,
                //all following packets are encoded in the compressed packet format.
                //Negative or zero values will disable compression,
                //meaning the packet format should remain in the uncompressed packet format.
                //However, this packet is entirely optional, and if not sent,
                //compression will also not be enabled (the notchian server does not send the packet when compression is disabled).
                if (packet_Id == 0x03)
                
                    //S->C : Set Compression (Optional)
                    int compression_threshold = ReadVarInt(stream);
                    Console.WriteLine($"packet_Id : packet_Id");
                

                //S->C : Login Success
                string uuid = ReadUUID(stream, 16);
                int name_length = ReadVarInt(stream);
                string name = ReadString(stream, name_length);
                
                Console.WriteLine($"uuid : uuid");
                Console.WriteLine($"name_length : name_length");
                Console.WriteLine($"name : name");
                
    public static string ReadUUID(Stream stream, int length)
    
        byte[] data = new byte[length];

        stream.Read(data);

        ulong b1 = BitConverter.ToUInt64(data,0);
        ulong b2 = BitConverter.ToUInt64(data,8);


        byte[] bytes = new byte[0];
        bytes = bytes.Concat(BitConverter.GetBytes(b1)).Concat(BitConverter.GetBytes(b2)).ToArray();

        string uuid = "";
        foreach (byte b in bytes)
            uuid += b.ToString("x2");

        return uuid.Substring(0, 8) + "-" + uuid.Substring(8, 4) + "-" + uuid.Substring(12, 4) + "-" + uuid.Substring(16, 4) + "-" + uuid.Substring(20, 12);
    

public static int ReadVarInt(Stream stream)

    int value = 0;
    int length = 0;
    int currentByte;

    while (true)
    
        currentByte = stream.ReadByte();
        value |= (currentByte & 0x7F) << (length++ * 7);
        if (length > 5) throw new IOException("VarInt too big");
        if ((currentByte & 0x80) != 0x80) break;
    
    return value;


public static string ReadString(Stream stream, int length)

    byte[] data = new byte[length];
    stream.Read(data);
    return Encoding.UTF8.GetString(data);

【讨论】:

以上是关于C# 使用 tcp/ip 从 Minecraft 服务器获取数据包的主要内容,如果未能解决你的问题,请参考以下文章

在 C# 5 中使用 async/await 模式编写高度可扩展的 TCP/IP 服务器?

在 C# 中实现 TCP/IP JSONRPC 连接 - 需要设计建议

C# Winforms 按钮到 Windows 中的特定屏幕

c#用TCP/IP协议打孔NAT网络

如何用C#语言 让pc与plc通过tcp ip互联

自动打开命名管道和 tcp\ip