2013-11-15 79 views
0

我有一個自己編寫的服務器客戶端程序。我正在使用TCP協議的套接字。我正試圖從客戶端發送緩衝區到服務器。該緩衝區結構,我將其轉換爲字節數組,把它和在服務器上我將其轉換回結構從字節數組:C#網絡 - 用StructLayout包發送結構緩衝區1

public static byte[] StructToByteArray(loginStruct obj) 
    { 
     int len = Marshal.SizeOf(typeof(loginStruct)); 
     byte[] arr = new byte[len]; 

     IntPtr ptr = Marshal.AllocHGlobal(len); 
     Marshal.StructureToPtr(obj, ptr, true); 
     Marshal.Copy(ptr, arr, 0, len); 

     Marshal.FreeHGlobal(ptr); 
     return arr; 

    } 
    public static void ByteArrayToStruct(byte[] buffer, ref loginStruct obj) 
    { 
     int len = Marshal.SizeOf(typeof(loginStruct)); 

     IntPtr i = Marshal.AllocHGlobal(len); 
     Marshal.Copy(buffer, 0, i, len); 
     obj = (loginStruct)Marshal.PtrToStructure(i, obj.GetType()); 

     Marshal.FreeHGlobal(i); 
    } 

我的結構:

[StructLayout(LayoutKind.Sequential, Pack = 1)] 
struct loginStruct 
{ 
    public string userName; 
    public string password; 

    public loginStruct(string userName, string password) 
    { 
     this.userName = userName; 
     this.password = password; 
    } 
} 

我得到一個運行時錯誤的行:

obj = (loginStruct)Marshal.PtrToStructure(i, obj.GetType()); 

錯誤是:

試圖讀取或寫入受保護的內存。這通常表明其他內存已損壞。

論功能ByteArrayToStruct len爲服務器等於緩衝區大小是16

回答

1

如果您要發送char *緩衝區固定大小的,那麼默認的編組字符串可能是不爲你工作。您應該使用MarshalAs屬性標記字符串並指定實際的緩衝區大小,以便.NET知道需要多少內存分配和複製到結構的非託管版本中。這將是這個樣子:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
struct loginStruct 
{ 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)] 
    public string userName; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=8)] 
    public string password; 

    public loginStruct(string userName, string password) 
    { 
     this.userName = userName; 
     this.password = password; 
    } 
} 

欲瞭解更多有關如何將字符串跨越受管理/非託管邊界編組,請參閱:Default Marshaling for Strings,特別是用於結構部分的字符串。

順便說一句,我不認爲你需要指定Pack,因爲你的數組是每個8字節,所以沒有空間填充。您需要非常確定您需要重寫結構上的包裝,特別是如果您的代碼需要在32位和64位系統上工作。如果C定義不包括#pragma pack或類似的,你可能不應該。

+0

謝謝。它幫助了我。我還有一個問題。如果我得到這個結構: 'struct user { string firstName; string lastName; } struct sendBuffer { string name; 列表 userList; }' 如何知道sendBuffer結構的大小? – user2320928

+1

如果您打算將結構發送到非託管代碼,我絕對會100%遠離C#容器類;你只是在乞求問題。使用sizeconst的數組和marshalas lparray。 –