2015-02-17 16 views
11

Tôi nhận được một mảng byte từ một socket và cấu trúc của các byte đơn giản là một mảng char lớn của các chuỗi có chiều rộng cố định. Trong một số trường hợp, trường cuối cùng là động (thay vì chiều dài cố định) và tôi đang cố Soạn các byte thành một cấu trúc. Tôi đã đọc rằng mảng char biến dài cần phải là IntPtr, nhưng tôi đã không tìm ra cách so sánh nó với các byte còn lại. Tôi cũng đã đọc trong một số bài viết mà tôi có thể cần một cấu trúc thứ hai, nhưng vẫn không thể tìm ra cách So sánh nó một cách chính xác.mảng byte [] để cấu trúc với mảng độ dài biến

Dưới đây là một ví dụ site

cách thích hợp để đối phó với mảng char chiều dài thay đổi trong cấu trúc là gì?

Các struct:

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

Chức năng:

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

này hoạt động - nhưng bây giờ Marshal.SizeOf (headerObj) cho biết đó là nhỏ hơn nó thực sự là khi tôi cố gắng chuyển đổi nó trở lại mảng byte []. Khác hơn thế, bất cứ điều gì sai với giải pháp này?

[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

Bạn nên nói lại và đặt câu hỏi thực tế. –

+0

mảng + 160 là phần còn lại của dữ liệu của bạn. 'Encoding.ASCII.GetString (mảng, 160, mảng.Length-160)' – EZI

+0

@EZI - đó là chính xác. Nếu mảng byte lớn hơn 160, mọi thứ khác là trường có độ dài thay đổi. –

Trả lời

10

Chỉ cần không cố gắng quá nhiều để làm cho các khai báo C# của bạn khớp chính xác với định dạng gói. Bạn sẽ thích điều này:

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

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

Bây giờ nó trở nên đơn giản. Bạn có thể sắp xếp các tiêu đề trong một ngã swoop và chỉ cần sao chép bất cứ điều gì byte thêm là hiện nay:

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

Và sửa đổi các lớp gói như bạn thấy phù hợp, bạn có thể muốn thêm một loạt các tính chất để đối phó với char [ ].

+0

Tôi coi giải pháp này là tốt, nhưng cũng đọc một bài báo sử dụng "dữ liệu cố định công cộng [1]" cũng khắc phục sự cố này, nhưng tôi không có nguồn hoàn chỉnh để xác định cách nó được sử dụng hoặc sắp xếp. Tôi có thể sẽ đi tuyến đường này vì mục đích an toàn, nhưng bạn có biết chúng có ý nghĩa gì trong bài viết sau không? http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_27480829.html –

+0

Tôi lấy ý tưởng của bạn và biến nó thành một phần của cấu trúc ban đầu, có thể không phải là giải pháp tốt nhất (xem câu hỏi chẳng hạn) và nó dường như làm việc cho deserialization, nhưng serializing nó trở lại một mảng byte [], tôi sẽ cần kích thước thực tế của đối tượng và không chỉ là sizeof (Header). Suy nghĩ ?? –

+0

Tôi coi một mảng một byte nhưng đã loại bỏ nó. Chương trình của bạn có thể gặp sự cố với AVE nếu bạn nhận được gói không có thêm dữ liệu. Có lẽ bạn có thể nhận được một đảm bảo rằng luôn luôn có một số, tôi không thể làm cho cùng một giả định. –