2013-11-15 31 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。 –