【问题标题】:Splitting up UDP packet拆分UDP数据包
【发布时间】:2015-12-19 21:48:05
【问题描述】:

我正在使用 UdpClient 向游戏服务器查询服务器名称、地图、玩家数量等信息。

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

我得到了正确的答复:

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

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

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

【问题讨论】:

    标签: c# udp packet


    【解决方案1】:

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

    你是如何得到回复的?

    1. 如果它已经在一个流中,那么您已经设置好了。
    2. 如果它在字节数组中,请先将其包装在MemoryStream 中。我认为UdpClient 是这样做的。

    然后,使用流构造一个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 页面上说这些是未签名的)

    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 而不是手动组装单个字节值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 1970-01-01
      • 1970-01-01
      • 2010-10-12
      • 2018-06-22
      • 1970-01-01
      相关资源
      最近更新 更多