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