开发者

Reading byte array to type/variable in a simplified way?

I have a TCP socket connection where I get byte array of data which I have to decrypt and then format, so I am looking for a simple way to read this resulted byte array that I can easyly walk thru the elements exporting it as I need to a type or variable etc, to explain it better see the below example:

Let's say we have the byte array (packets are little-endian, this is just hypotetical example):

01 02 00 03 74 00 74 00 69 00

I want to put the first 2 bytes into an int, the next 2 bytes into another int and rest as an string.

So it would look like this translated:

int first = 258;
int seconnd = 3;
string rest = "tti"

I am not a java person, but on java there was something interesting I noticed somewhere of people reading packets directly like this:

messageSize = readH(); // for 2 bytes
key = readH(); // for 2 bytes
message = readS();开发者_运维知识库 // read as string

And I was wondering if there is similar pre-made feature in c# or any other resource that may help me better doing this task ?


You can use BinaryReader like this:

using (var reader = new BinaryReader(stream))
{
    var first = reader.ReadUInt16();
    var second = reader.ReadUInt16();
    var stringBytes = reader.ReadBytes(6);
    var str = Encoding.Unicode.GetString(stringBytes);
}

However, this will only work if little-endian is used.

The example you posted is big-endian.

I assume that you implement both writer and sender in C#, so you are good to go with BinaryReader and BinaryWriter, they both use little-endian, so they will understand each other.

[Edit]

Another approach you might want to consider is using struct.
For example in your case :

[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct MyStruct
{
    public ushort First;
    public ushort Second;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 10)]
    public string MyString;
}

The code would look like this

var myStruct = new MyStruct { First = 1, Second = 2, MyString = "asd" };

var bytes = StructToBytes(myStruct);

var myStruct1 = BytesToStruct<MyStruct>(bytes);

And two utility methods:

public static T BytesToStruct<T>(byte[] bytes) where T : struct
{
    AssertUtilities.ArgumentNotNull(bytes, "bytes");

    var structSize = Marshal.SizeOf(typeof(T));
    var pointer = IntPtr.Zero;
    try
    {
        pointer = Marshal.AllocHGlobal(structSize);
        Marshal.Copy(bytes, 0, pointer, structSize);
        return (T)Marshal.PtrToStructure(pointer, typeof(T));
    }
    finally
    {
        if (pointer != IntPtr.Zero)
            Marshal.FreeHGlobal(pointer);
    }
}

public static byte[] StructToBytes<T>(T structObject) where T : struct
{
    var structSize = Marshal.SizeOf(typeof(T));
    var bytes = new byte[structSize];
    var pointer = IntPtr.Zero;
    try
    {
        pointer = Marshal.AllocHGlobal(structSize);
        Marshal.StructureToPtr(structObject, pointer, true);
        Marshal.Copy(pointer, bytes, 0, structSize);
        return bytes;
    }
    finally
    {
        if (pointer != IntPtr.Zero)
            Marshal.FreeHGlobal(pointer);
    }
}


For simple examples, you could do something like:

static class StreamHelpers
{
    public static int ReadH(this Stream stream)
    {
        int x = stream.ReadByte(), y = stream.ReadByte();
        if (x < 0 || y < 0) throw new EndOfStreamException();
        return (y << 8) | x;
    }
    ...

}

which gives you access to:

int i = stream.ReadH();

etc. However, personally I would be writing a custom blahReader (for your blah), with an internal byte[] buffer and tracking cursor. This allows must more efficient reading in most cases (even compared to a BufferedStream).

As a side-note, your string looks to be UTF-16 and read to the EOF; reading to EOF is a pain as it doesn't really allow you to encode 2 strings. I would (instead) be adding (first) the length of the string, and I would be using UTF-8 unless there is a good chance of large character points. Then reading a string is a case of:

  • read the length
  • decode that much via Encoding.*

As a final point - if you are mostly writing small integers, there are alternative encoding styles for integers that might be useful (allowing single-byte for small values, but still allowing full int ranges to be expressed).

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜