C#用socket传输类或结构,以及结构和bytes[]互转

来源:互联网 发布:网络彩票与实体店结合 编辑:程序博客网 时间:2024/06/10 03:14

最近有一项目,是和另外一家公司合作,需要接收对方发来的结构消息,然后填充好后发回。

涉及到利用socket传输和接收struct。

一般情况下我们只需要利用C#提供的序列化和反序列化即可,将class/struct声明为可序列化的。

然后利用BinaryFormatter之类的方法进行序列化及反序列化操作~自己可以Google一下:C#序列化

但是假如对方平台为C++或其它非.NET平台,这样做就不行了。由于不同平台类型之间的差异,

所以有不小的麻烦。

先附上C++与C#之间的类型对应关系:

C++输入输出 C# char chr[255]OStringBuilder KCA_DIRIint LPCSTRIstring intIint LPSTROStringBuilder int*Oout intDWORDIint DWORD*Oout intBOOLIbool Rc_DBMgrIIntPtr long*Oout long
API与C#的数据类型对应关系表API数据类型类型描述C#类型API数据类型类型描述C#类型WORD16位无符号整数ushortCHAR字符charLONG32位无符号整数intDWORDLONG64位长整数longDWORD32位无符号整数uintHDC设备描述表句柄intHANDLE句柄,32位整数intHGDIOBJGDI对象句柄intUINT32位无符号整数uintHINSTANCE实例句柄intBOOL32位布尔型整数boolHWM窗口句柄intLPSTR指向字符的32位指针stringHPARAM32位消息参数intLPCSTR指向常字符的32位指针StringLPARAM32位消息参数intBYTE字节byteWPARAM32位消息参数int

Wtypes.h
中的非托管类型
非托管C语言类型托管类名说明HANDLEvoid*System.IntPtr32 位BYTEunsigned charSystem.Byte8 位SHORTshortSystem.Int1616 位WORDunsigned shortSystem.UInt1616 位INTintSystem.Int3232 位UINTunsigned intSystem.UInt3232 位LONGlongSystem.Int3232 位BOOLlongSystem.Int3232 位DWORDunsigned longSystem.UInt3232 位ULONGunsigned longSystem.UInt3232 位CHARcharSystem.Char用 ANSI 修饰。LPSTRchar*
System.String或
System.StringBuilder
用 ANSI 修饰。LPCSTRConst char*
System.String
或System.StringBuilder
用 ANSI 修饰。LPWSTRwchar_t*
System.String
或System.StringBuilder
用 Unicode 修饰。LPCWSTRConst wchar_t*
System.String
或System.StringBuilder
用 Unicode 修饰。FLOATFloatSystem.Single32 位DOUBLEDoubleSystem.Double64 位

需要注意的是非托管的BOOL在C#中对应System.Int32。而在API调用时直接用bool即可。

socket传输的是byte[].所以我们需要把struct转化为byte[]. 有高人为我们提供了如下方法。

//struct转换为byte[]static byte[] StructToBytes(object structObj) { int size = Marshal.SizeOf(structObj); IntPtr buffer = Marshal.AllocHGlobal(size); try { Marshal.StructureToPtr(structObj, buffer, false); byte[] bytes = new byte[size]; Marshal.Copy(buffer, bytes, 0, size); return bytes; } finally { Marshal.FreeHGlobal(buffer); } } //byte[]转换为structstatic object BytesToStruct(byte[] bytes, Type strcutType) { int size = Marshal.SizeOf(strcutType); IntPtr buffer = Marshal.AllocHGlobal(size); try { Marshal.Copy(bytes, 0, buffer, size); return Marshal.PtrToStructure(buffer, strcutType); } finally { Marshal.FreeHGlobal(buffer); } }

一般情况下到此就结束了。但是假如struct里面除了基本数据类型int,long,byte之外,还有 char*.比如:

typedef struct{   char szStatus[924];    char szError[196];   BYTE bEmergent;} CHECK_STATUS_PARAM

为了确保数据传输和读取的正确性,应该固定字符串的长度。

此处就涉及到了:字符串的封送处理。见:http://msdn.microsoft.com/zh-cn/library/s9ts558h(VS.80).aspx

在不同的情况下我们需要采用不同的封送选项。

结构中使用的字符串

字符串是结构的有效成员;但是,StringBuilder 缓冲区在结构中是无效的。下表显示当字符串数据类型被作为字段封送时该类型的封送处理选项。MarshalAsAttribute 属性提供了若干个 UnmanagedType 枚举值,以便将字符串封送到字段。

枚举类型  非托管格式的说明

UnmanagedType.BStr  

具有预设长度和 Unicode 字符的 COM 样式的 BSTR。

UnmanagedType.LPStr  

指向 ANSI 字符的空终止数组的指针。

UnmanagedType.LPTStr 

指向平台相关的字符的空终止数组的指针。

UnmanagedType.LPWStr 

指向 Unicode 字符的空终止数组的指针。

UnmanagedType.ByValTStr 

定长的字符数组;数组的类型由包含数组的结构的字符集确定。

项目要求采用ANSI编码,于是C#对应的stuctr为:

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]public struct CHECK_STATUS_PARAM{[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 924 )]public string szStatus;[MarshalAs( UnmanagedType.ByValTStr, SizeConst = 196 )]public string szError;public byte bEmergent;}


原创粉丝点击