応答形式は、基本的に構造体のように、応答パケット内のフィールドの順序とタイプを提供します。のようなクラスを使用BinaryReader
して、パケット内のバイトのグループを読み取り、それらを適切なデータ型として解釈できます。
どのように応答を得ていますか?
- すでにストリームに含まれている場合は、設定されています。
- バイト配列の場合は、
MemoryStream
最初にラップします。私UdpClient
はそれをこのようにすると思います。
次に、BinaryReader
ストリームを使用してを作成します。ストリームとリーダーの両方がである必要があることを忘れないでくださいDisposed
。
BinaryReader reader = new BinaryReader(stream);
ReadByte
これで、などのリーダーのメソッドを呼び出してReadInt32
、フィールドのタイプに対応するメソッドを使用して、応答から各フィールドを順番に読み取ることができます。ストリームは読み取られるときに内部オフセットを更新するため、応答バッファーの適切な場所から連続するフィールドを自動的に読み取ります。 BinaryReader
Steamパケットで使用される5つの非文字列タイプに適したメソッドがすでにあります。
byte: ReadByte
short: ReadInt16
long: ReadInt32
float: ReadSingle
long long: ReadUInt64
(はい、そこにUがあります。Valveページにはこれらは署名されていないと書かれています)
string
は、Valve(nullで終了するUTF-8)で指定された形式の文字列を読み取るメソッドがまだないため、少しBinaryReader
注意が必要です。したがって、バイトごとに自分で行う必要があります。他の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
個々のバイト値を手動で組み立てる代わりに、同様のコードを使用してリクエストパケットを作成できます。