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

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

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

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

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

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

所以有不小的麻烦。

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

C++                      输入输出                    C#
==================================
char chr[255]              O               StringBuilder
KCA_DIR                     I                         int
LPCSTR                       I                  string
int                              I                    int
LPSTR                        O            StringBuilder
int*                            O               out int
DWORD                      I                   int
DWORD*                    O               out int
BOOL                          I                     bool
Rc_DBMgr                   I                     IntPtr
long*                          O               out long

API与C#的数据类型对应关系表
API数据类型 类型描述 C#类型 API数据类型 类型描述 C#类型
WORD 16位无符号整数 ushort CHAR 字符 char
LONG 32位无符号整数 int DWORDLONG 64位长整数 long
DWORD 32位无符号整数 uint HDC 设备描述表句柄 int
HANDLE 句柄,32位整数 int HGDIOBJ GDI对象句柄 int
UINT 32位无符号整数 uint HINSTANCE 实例句柄 int
BOOL 32位布尔型整数 bool HWM 窗口句柄 int
LPSTR 指向字符的32位指针 string HPARAM 32位消息参数 int
LPCSTR 指向常字符的32位指针 String LPARAM 32位消息参数 int
BYTE 字节 byte WPARAM 32位消息参数 int

Wtypes.h 中的非托管类型

非托管 C 语言类型

托管类名

说明

HANDLE

void*

System.IntPtr

32

BYTE

unsigned char

System.Byte

8

SHORT

short

System.Int16

16

WORD

unsigned short

System.UInt16

16

INT

int

System.Int32

32

UINT

unsigned int

System.UInt32

32

LONG

long

System.Int32

32

BOOL

long

System.Int32

32

DWORD

unsigned long

System.UInt32

32

ULONG

unsigned long

System.UInt32

32

CHAR

char

System.Char

ANSI 修饰。

LPSTR

char*

System.String System.StringBuilder

ANSI 修饰。

LPCSTR

Const char*

System.String System.StringBuilder

ANSI 修饰。

LPWSTR

wchar_t*

System.String System.StringBuilder

Unicode 修饰。

LPCWSTR

Const wchar_t*

System.String System.StringBuilder

Unicode 修饰。

FLOAT

Float

System.Single

32

DOUBLE

Double

System.Double

64

 需要注意的是非托管的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[]转换为struct
static 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#对应的stuct为:

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

为了保证正确性,使对象的各个成员在非托管内存中的精确位置被显式控制。我们也可以使用FieldOffsetAttribute指示该字段在类型中的位置。此方法只有在LayoutKind设置为Explicit时使用。 。

作者:一修先生
         
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/1971ruru/p/struct.html