【问题标题】:c# using marshalling for packet parsingc# 使用编组进行数据包解析
【发布时间】:2013-08-14 17:26:00
【问题描述】:

例如,我必须解析以 ascii 代码存储在 byte[] 中的数据包 字节[] 用户 = 新字节[] {112, 114, 97, 116, 121, 117, 115, 104, 0, 0, 0, 0, 49, 50, 51, 0} 其中前 12 个字节是服务器名称,后四个字节是一些 id。

通过查看以前的 stackoverflow 帖子,我想出了这段代码

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

当我运行此代码时,我的输出是 7526488566770266736 的服务器名称和 13106 的 imei_msn,这可能是 ascii->hex->decimal 格式。现在我面临的问题是,如何将这些数字转换为一些有意义的完整信息,例如第一个转换为显示名称的字符串,第二个转换为十进制格式的 imei_msn?

【问题讨论】:

  • 预期值是多少?在您的样本数据中pratyushservername,但imei_msn 是什么?
  • imei_msn 应该是 123

标签: c# marshalling


【解决方案1】:

尝试使用固定大小的数组(阅读此处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;
};

然后从那里:

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

或直接作为属性

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

记住TrimEnd'\0' 中的所有byte[]

你确定编码是ASCII吗?尝试在名称中添加一些带有重音符号的字母,例如 àèéìòù... 也许是 UTF8。或者它正在使用Default 编码。

【讨论】:

  • 感谢您的解决方案,我已经解决了我的问题。我想确认的另一件事而不是 SizeConst 是他们的变量字段选项,以防数据大小可变。
  • @user2673943 No. SizeConst 在编译时必须是已知的常量。请注意,我刚刚在代码中添加了一些关于 TrimEnd() 的评论。
【解决方案2】:

尝试将您的 servername1servername12 字节添加到 byte[12] 数组中,并使用以下方法从中拉出一个字符串

byte[] array = GetBytesOfServerName();
string serverName = Encoding.ASCII.GetString(array);

【讨论】:

  • 感谢您的解决方案
【解决方案3】:

如果您可以在项目中使用 /unsafe,您可以像这样使用固定缓冲区:

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

    [FieldOffset(12)]
    public Int32 imei_msn;
}

【讨论】:

    【解决方案4】:

    这应该可行:

    string serverName = Encoding.ASCII.GetString(user.Take(12).ToArray());
    string imeiMsn = Encoding.ASCII.GetString(user.Skip(12).ToArray());
    Console.WriteLine(serverName);
    Console.WriteLine(imeiMsn);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-12
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-02
      • 2011-12-31
      • 2011-06-30
      相关资源
      最近更新 更多