拆分UDP数据包

时间:2010-06-10 16:38:52

标签: c# udp packet

我正在使用UdpClient查询游戏服务器的服务器名称,地图,玩家数量等。

我已按照此页面上的指南(A2S_INFO) http://developer.valvesoftware.com/wiki/Server_queries#Source_servers

我收到了正确答复:

alt text http://data.fuskbugg.se/skalman01/reply.JPG

我不知道如何获取每一块信息(服务器名称,地图等)。

有任何帮助吗?我假设我必须查看我链接的wiki中指定的回复格式,但我不知道该怎么做。

1 个答案:

答案 0 :(得分:6)

回复格式为您提供回复数据包中字段的顺序和类型,基本上类似于结构。您可以使用类似BinaryReader的类来读取数据包中的字节组,并将它们解释为适当的数据类型。

你是如何得到回应的?

  1. 如果它已经在流中,那么你已经设置好了。
  2. 如果它在字节数组中,请先将其包装在MemoryStream中。我认为UdpClient就是这样做的。
  3. 然后,使用流构建BinaryReader。请记住,流和阅读器都必须是Disposed

    BinaryReader reader = new BinaryReader(stream);
    

    您现在可以使用ReadByteReadInt32等方式调用阅读器的方法,使用与字段类型对应的方法依次从响应中读取每个字段。流在读取时更新其内部偏移量,因此您可以自动从响应缓冲区中的正确位置读取连续字段。 BinaryReader已经有适合Steam数据包中使用的五种非字符串类型的方法:

    1. byte: ReadByte
    2. short: ReadInt16
    3. long: ReadInt32
    4. float: ReadSingle
    5. long long: ReadUInt64(是的,那里有一个U; Valve页面说这些是未签名的)
    6. string有点棘手,因为BinaryReader还没有方法来读取Valve指定的格式的字符串(以null结尾的UTF-8),所以你必须这样做它自己,逐字节。为了使它看起来像任何其他BinaryReader方法一样,你可以写一个扩展方法(未经测试的代码;这是它的要点):

      public static string ReadSteamString(this BinaryReader reader)
      {
        // To hold the list of bytes making up the string
        List<byte> str = new List<byte>();
        byte nextByte = reader.ReadByte();
        // Read up to and including the null terminator...
        while (nextByte != 0)
        {
          // ...but don't include it in the string
          str.Add(nextByte);
          nextByte = reader.ReadByte();
        }
      
        // Interpret the result as a UTF-8 sequence      
        return Encoding.UTF8.GetString(str.ToArray());
      }
      

      一些示例用法,包含您提供的响应数据包:

      // Returns -1, corresponding to FF FF FF FF
      int header = reader.ReadInt32();
      // Returns 0x49, for packet type
      byte packetType = reader.ReadByte();
      // Returns 15, for version
      byte ver = reader.ReadByte();
      // Returns "Lokalen TF2 #03 All maps | Vanilla"
      string serverName = reader.ReadSteamString();
      // Returns "cp_well"
      string mapName = reader.ReadSteamString();
      // etc.
      

      您可以使用类似的代码创建请求数据包,使用BinaryWriter而不是手动汇编单个字节值。