开发者

Problem with code converted from C++ to C#

I converted some code from a C++ application I wrote a long time ago to C#. In C++ I had a library I used that was a bit buffer, but my lack of C# knowledge has somewhat complicated the conversion.

When I query my application, and I simply use a ByteWriter without casting any values properly (just like bf.Write(-1) and bf.Write("stringhere") the query programs atleast query it, just get the wrong information. When I cast the values properly (to long, byte, short, etc) it completely breaks, and the query application doesn't even see it anymore.

C++ Code Snippet

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

    g_ReplyInfo.WriteLong(-1);
    g_ReplyInfo.WriteByte(73);
    g_ReplyInfo.WriteByte(g_ProtocolVersion.GetInt(开发者_StackOverflow社区));
    g_ReplyInfo.WriteString(iserver->GetName());    
    g_ReplyInfo.WriteString(iserver->GetMapName()); 
    g_ReplyInfo.WriteString(gGameType);
}

C# Code

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();
}


A couple of ideas that might get you on track:

  1. Are you sure you need UTF8 as string encoding?
  2. When you look at the array and compare it to the intended structure, are you able to find out at what point the array does not comply to the standard?


Just a few things to keep in mind:

  1. UTF-8 strings sometimes start with a BOM (byte order mark), sometimes not.
  2. Strings sometimes are serialized length prefixed, sometimes null-terminated.

My suggestion is to double-check the original C++ method WriteString(...) to find out how it behaves with respect to #1 and #2, and then to double-check the C# method GetBytes(...) for the same. If I recall, the .NET binary serializer writes length-prefixed strings for each string written, but the UTF8 encoder does not (and does not output a null character either). The UTF8 encoder may also (depending on how you use it?) output a BOM.

Also, I'm suspicious of how \0 might be written out when passing through the UTF8 encoder. You might (for kicks) try outputting the null marker separately from the string content, as just a 0-valued byte.


Long size in C# was different from C++, resolved the issue.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜