Формат ответа дает вам порядок и тип полей в пакете ответа, в основном, как структура. Вы можете использовать класс типа BinaryReader
для чтения групп байтов в пакете и интерпретировать их как соответствующие типы данных.
Как вы получаете ответ?
- Если он уже в потоке, вы настроены.
- Если он находится в байтовом массиве, сначала оберните его в
MemoryStream
. Я думаю UdpClient
делает это так.
Затем создайте BinaryReader
, используя поток. Помните, что поток и читатель должны быть Disposed
из.
BinaryReader reader = new BinaryReader(stream);
Теперь вы можете вызывать методы читателя, такие как ReadByte
, ReadInt32
и т. Д., Чтобы читать каждое поле по очереди из ответа, используя методы, соответствующие типам полей. Поток обновляет свое внутреннее смещение по мере чтения, поэтому вы автоматически читаете последовательные поля из нужного места в буфере ответов. BinaryReader
уже имеет методы, соответствующие пяти нестроковым типам, используемым в пакетах Steam:
byte: ReadByte
short: ReadInt16
long: ReadInt32
float: ReadSingle
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
вместо ручной сборки отдельных значений байтов.