1

昔書いたC++アプリケーションのコードをC#に変換しました。C ++では、ビットバッファーであるライブラリを使用していましたが、C#の知識が不足しているため、変換がやや複雑になっています。

アプリケーションにクエリを実行し、値を適切にキャストせずにByteWriterを使用すると(bf.Write(-1)やbf.Write( "stringhere")のように、クエリプログラムは少なくともクエリを実行しますが、間違った情報を取得するだけです。値を適切に(long、byte、shortなどに)キャストすると、完全に壊れてしまい、クエリアプリケーションはそれを認識しなくなります。

C++コードスニペット

void PlayerManager::BuildReplyInfo()
{   
    // Delete the old packet
    g_ReplyInfo.Reset();

    g_ReplyInfo.WriteLong(-1);
    g_ReplyInfo.WriteByte(73);
    g_ReplyInfo.WriteByte(g_ProtocolVersion.GetInt());
    g_ReplyInfo.WriteString(iserver->GetName());    
    g_ReplyInfo.WriteString(iserver->GetMapName()); 
    g_ReplyInfo.WriteString(gGameType);
}

C#コード

public static byte[] ConvertStringToByteArray(string str)
{
    System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
    return encoding.GetBytes(str);
}

// ---------------------------------------------------

    while (true)
    {
        data = new byte[1024];
        recv = socket.ReceiveFrom(data, ref Remote);

        Console.WriteLine("Message length is " + recv);

        // If the length is 25 and the 5th byte is 'T' it is a A2S_INFO QUERY
        if (recv == 25 && data[4] == 84)
        {
            Console.WriteLine("Source Engine Query!");

            data = BuildReplyInformation();
            socket.SendTo(data, 0, data.Length, SocketFlags.None, Remote);
        }
    }
}

public static byte[] BuildReplyInformation()
{
    MemoryStream stream = new MemoryStream();
    BinaryWriter writer = new BinaryWriter(stream);

    writer.Write((long)(-1));
    writer.Write((byte)(73)); // Steam Version
    writer.Write((byte)(15)); // Protocol
    writer.Write(ConvertStringToByteArray("Minecraft Server\0")); // Hostname
    writer.Write(ConvertStringToByteArray("Map Name\0")); // Map Name
    writer.Write(ConvertStringToByteArray("tf\0")); // Game Directory
    writer.Write(ConvertStringToByteArray("Minecraft Server\0")); // Game Description
    writer.Write((short)(440));
    writer.Write((byte)(15)); // Players
    writer.Write((byte)(32)); // Max Players
    writer.Write((byte)(0)); // Bots
    writer.Write((byte)(100));
    writer.Write((byte)(119)); // 108 Linux, 119 Windows
    writer.Write((byte)(0)); // Password Boolean
    writer.Write((byte)(01)); // Vac Secured
    writer.Write(ConvertStringToByteArray("1.1.3.7\0"));

    return stream.ToArray();
}
4

3 に答える 3

0

あなたを軌道に乗せるかもしれないいくつかのアイデア:

  1. 文字列エンコーディングとしてUTF8が必要ですか?
  2. アレイを見て目的の構造と比較すると、アレイが標準に準拠していないポイントを見つけることができますか?
于 2011-03-12T08:42:35.653 に答える
0

留意すべき点がいくつかあります。

  1. UTF-8 文字列は、BOM (バイト オーダー マーク) で始まる場合とそうでない場合があります。
  2. 文字列は、シリアル化された長さのプレフィックスが付けられたり、null で終了したりすることがあります。

私の提案は、元の C++ メソッド WriteString(...) をダブルチェックして、それが #1 と #2 に関してどのように動作するかを調べてから、同じものについて C# メソッド GetBytes(...) をダブルチェックすることです。 . 思い出すと、.NET バイナリ シリアライザーは、書き込まれた文字列ごとに長さがプレフィックスされた文字列を書き込みますが、UTF8 エンコーダーは書き込みません (また、null 文字も出力しません)。UTF8 エンコーダーは (使い方によっては?) BOM を出力することもあります。

また、UTF8 エンコーダーを通過するときに \0 がどのように書き出されるのか疑問です。(キックのために) null マーカーを文字列の内容とは別に、値が 0 のバイトとして出力してみてください。

于 2011-03-12T08:50:11.317 に答える
0

C# の long サイズが C++ とは異なり、問題が解決されました。

于 2011-03-12T12:00:18.797 に答える