2015-02-17 81 views
11

我收到来自套接字的字节数组和字节的结构只是一个固定宽度的字符串的大型字符数组。在某些情况下,最后一个字段是动态的(而不是固定的长度),我试图将字节编组为一个结构。我读过可变长字符数组需要是IntPtr,但我还没有想出如何用剩余的字节对它进行编组。我也读过一些文章,可能需要第二种结构,但仍然无法弄清楚如何正确编组。字节[]数组结构与可变长度数组

这里有一个这样的site

什么是应对结构变长字符数组的正确方法?

的结构:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct Header 
{ 
    #region private member fields 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f1; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f2; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f3; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f4; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f5; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f6; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] 
    private char[] _f7; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] 
    private char[] _f8; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] 
    private char[] _f9; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] 
    private char[] _f10; 

    // how would this get filled with a char[] array from the byte array? 
    public IntPtr VariableLengthData; 

    #endregion 
} 

功能:

public static Header FromArray(byte[] array) 
{ 
    IntPtr buff = IntPtr.Zero; 

    try 
    { 
     int objsize = Marshal.SizeOf(typeof(Header)); 
     buff = Marshal.AllocHGlobal(objsize); 
     Marshal.Copy(array, 0, buff, objsize); 
     var result = (Header)Marshal.PtrToStructure(buff, typeof(HostHeader)); 

     // the variable length data needs to be filled in somehow 
     // but also note that an extra 4 bytes was added to the size 
     // of the struct with the IntPtr 
     if(objsize < array.Length) 
     { 
      Marshal.Copy(array, array.Length - objsize, result.VariableLengthData, array.Length - objsize); 
     } 

     return result; 
    } 
    finally 
    { 
     if (buff != IntPtr.Zero) 
     { 
      Marshal.FreeHGlobal(buff); 
      buff = IntPtr.Zero; 
     } 
    } 
} 

这工作 - 但现在Marshal.SizeOf(headerObj)说,这是小于它确实是,当我试图将其转换回一个byte []数组。除此之外,这个解决方案有什么问题吗?

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
public struct Header 
{ 
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field1; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field2; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] 
    public char[] Field3; 

    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] 
    public char[] Field4; 
} 

public static Header DeserializeHeader(byte[] data) 
{ 
    int objsize = Marshal.SizeOf(typeof(Header)); 
    IntPtr buff = Marshal.AllocHGlobal(objsize); 
    Marshal.Copy(data, 0, buff, objsize); 
    var header = (Header)Marshal.PtrToStructure(buff, typeof(Header)); 
    Marshal.FreeHGlobal(buff); 

    // resize Field4 to hold all the remaining bytes 
    if(objsize < data.Length) 
    { 
     header.Field4 = Encoding.ASCII.GetChars(data, objsize - header.Field4.Length, data.Length - objsize - header.Field4.Length); 
    } 
    return header; 
} 
+0

你应该改写并输入一个实际的问题。 – 2015-02-17 21:10:13

+0

array + 160是您的其余数据。 'Encoding.ASCII.GetString(array,160,array.Length-160)' – EZI 2015-02-17 21:21:26

+0

@EZI - 这是正确的。如果字节数组大于160,则其他所有内容都是可变长度字段。 – 2015-02-17 21:30:03

回答

10

只是不要试图让你的C#声明完全匹配数据包格式。你会喜欢这个:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] 
public class Header { 
    //.... 
} 

public class Packet { 
    public Header Header; 
    public byte[] VariableLengthData; 
} 

现在它变得简单。您可以名帅一举头,只是复制任何额外的字节存在:

static unsafe Packet FromArray(byte[] data) { 
    var hdrsize = Marshal.SizeOf(typeof(Header)); 
    if (data.Length < hdrsize) throw new ArgumentException(); 
    Packet result = new Packet(); 
    // Marshal the header 
    fixed (byte* pdata = &data[0]) { 
     result.Header = (Header)Marshal.PtrToStructure(new IntPtr(pdata), typeof(Header)); 
    } 
    // Copy the rest 
    var varsize = data.Length - hdrsize; 
    result.VariableLengthData = new byte[varsize]; 
    Array.Copy(data, hdrsize, result.VariableLengthData, 0, varsize); 
    return result; 
} 

并修改数据包类,您认为合适,你可能想添加了一堆的属性来处理的char [ ]。

+0

我也考虑过这个解决方案,但也阅读了一篇使用“public fixed char Data [1]”的文章也解决了这个问题,但我没有完整的来源来确定它是如何被使用或编组的。为了安全起见,我可能会走这条路线,但是您是否知道它在下面的文章中的含义? http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_27480829.html – 2015-02-20 13:38:29

+0

我把你的想法变成了原始结构的一部分,这可能不是最好的解决方案(例如见问题),它似乎适用于反序列化,但将其序列化回byte []数组,我将需要对象的实际大小,而不仅仅是sizeof(Header)。思考? – 2015-02-20 13:53:06

+0

我考虑过一个字节的数组,但不考虑它。如果您收到没有额外数据的数据包,您的程序可能会与AVE崩溃。也许你可以得到保证,总有一些,我不能做出相同的假设。 – 2015-02-20 15:29:57