2010-06-10 5 views
2

Я использую UdpClient для запроса игровых серверов о имени сервера, карты, количество игроков и т.д.Разделение пакетов UDP

Я следовал указаниям на этой странице (A2S_INFO) http://developer.valvesoftware.com/wiki/Server_queries#Source_servers

и я получаю правильный ответ:

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

Я понятия не имею, как я бы идти о получить каждый кусок информации (имя сервера, карты и тому подобное).

Любая помощь? Я предполагаю, что нужно смотреть на формат ответа, указанный в связанной с wiki, но я не знаю, что с этим делать.

ответ

5

Формат ответа дает вам порядок и тип полей в пакете ответов, в основном как struct. Вы можете использовать класс, например BinaryReader, для чтения групп байтов в пакете и интерпретации их как соответствующих типов данных.

Как вы получаете ответ?

  1. Если вы уже в потоке, вы настроены.
  2. Если он находится в массиве байтов, сначала оберните его в MemoryStream. Думаю UdpClient делает так.

Затем постройте BinaryReader, используя поток. Помните, что и поток, и читатель должны быть Disposed.

BinaryReader reader = new BinaryReader(stream); 

Теперь вы можете вызывать методы читателя как ReadByte, ReadInt32 и т.д., чтобы прочитать каждое поле в своей очереди, от ответа, используя методы, соответствующие типам Полей. Поток обновляет свое внутреннее смещение по мере его чтения, поэтому вы автоматически читаете последовательные поля из нужного места в буфере ответов. BinaryReader уже есть методы, подходящие для пяти типов нестроковых, используемых в паровых пакетах:

  1. byte: ReadByte
  2. short: ReadInt16
  3. long: ReadInt32
  4. float: ReadSingle
  5. long long: ReadUInt64 (да, есть U там; на странице Valve указано, что они без знака)

string немного сложнее, потому что BinaryReader еще не имеет методов для чтения строк в формате, указанном Valve (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 вместо того, чтобы вручную сборки отдельных значений байтов.

Смежные вопросы