c# using marshalling for packet parsing

2019-09-09 05:41发布

I have to parse a packet which is stored in byte[] in ascii code for example byte[] user = new byte[] {112, 114, 97, 116, 121, 117, 115, 104, 0, 0, 0, 0, 49, 50, 51, 0} where first 12 bytes are servername and last four bytes are some id.

By going through previous stackoverflow posts I came up with this code

[StructLayout(LayoutKind.Explicit)]
struct packetrf
{
  public ulong servername
    {
        get
        {
            return (ulong)servername1 | ((ulong)servername2 << 8) | ((ulong)servername3 << 16) | ((ulong)servername4 << 24) | ((ulong)servername5 << 32) | ((ulong)servername6 << 40) | ((ulong)servername7 << 48) | ((ulong)servername8 << 56) | ((ulong)servername9 << 64) | ((ulong)servername10 << 72) | ((ulong)servername11 << 80) | ((ulong)servername12 << 88);
        }
    }

    [FieldOffset(0)]
    public byte servername1;

    [FieldOffset(1)]
    public byte servername2;

    [FieldOffset(2)]
    public byte servername3;

    [FieldOffset(3)]
    public byte servername4;

    [FieldOffset(4)]
    public byte servername5;

    [FieldOffset(5)]
    public byte servername6;

    [FieldOffset(6)]
    public byte servername7;

    [FieldOffset(7)]
    public byte servername8;

    [FieldOffset(8)]
    public byte servername9;

    [FieldOffset(9)]
    public byte servername10;

    [FieldOffset(10)]
    public byte servername11;

    [FieldOffset(11)]
    public byte servername12;

   [FieldOffset(12)]
    public Int32 imei_msn;
};

static private pack fromByte(byte[] arr)
{
    pack str = new pack();
    GCHandle handle = GCHandle.Alloc(arr, GCHandleType.Pinned);
    str = (pack)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(pack));
    handle.Free();
    return str;
}

static private void data_parser(byte[] pkt, int size, int indexno)
{
       packetrf data = fromByte(pkt);
        Console.WriteLine();
        Console.WriteLine(data.servername);
        Console.WriteLine(data.imei_msn);
        Console.ReadKey();
    }


public static void Main()
{
    byte[] user = new byte[] {112, 114, 97, 116, 121, 117, 115, 104, 0, 0, 0, 0, 49, 50, 51, 0}
    data_parser(user, 1, 2);
}

When I run this code my output is 7526488566770266736 for servername and 13106 for imei_msn which is probably is probably ascii->hex->decimal format. Now the problem I am facing is that how can I convert these numbers to some meaning full information like first one to string showing name and second one to imei_msn in decimal format?

4条回答
女痞
2楼-- · 2019-09-09 06:11

Try using fixed-size arrays (read here https://stackoverflow.com/a/14629106/613130)

[StructLayout(LayoutKind.Explicit)]
struct packetrf
{
    [FieldOffset(0), MarshalAs(UnmanagedType.ByValArray, SizeConst=12)]
    public byte[] servername;

    [FieldOffset(12)]
    public Int32 imei_msn;
};

Then from there:

string serv = Encoding.ASCII.GetString(yourObject.servername).TrimEnd('\0');

or directly as a property

public string serverName2
{
    get
    {
        return Encoding.ASCII.GetString(servername).TrimEnd('\0');
    }
}

And remember to TrimEnd all those '\0' that there will be in the byte[].

Are you sure the encoding is ASCII? Try putting in the name some letters with accents, like àèéìòù... Perhaps it's UTF8. or perhaps it's using the Default encoding.

查看更多
一夜七次
3楼-- · 2019-09-09 06:12

This should work:

string serverName = Encoding.ASCII.GetString(user.Take(12).ToArray());
string imeiMsn = Encoding.ASCII.GetString(user.Skip(12).ToArray());
Console.WriteLine(serverName);
Console.WriteLine(imeiMsn);
查看更多
狗以群分
4楼-- · 2019-09-09 06:27

If you are okay with using /unsafe with your project, you can use fixed buffer like this:

[StructLayout(LayoutKind.Explicit)]
unsafe struct packetrf
{
    [FieldOffset(0)]
    public fixed byte[12] servername;

    [FieldOffset(12)]
    public Int32 imei_msn;
}
查看更多
Ridiculous、
5楼-- · 2019-09-09 06:33

Try adding your servername1servername12 bytes into a byte[12] array and pull a string out of it by using

byte[] array = GetBytesOfServerName();
string serverName = Encoding.ASCII.GetString(array);
查看更多
登录 后发表回答