2015-02-17 79 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