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

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

涉及到利用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 int
DWORDIint 
DWORD*Oout int
BOOLIbool 
Rc_DBMgrIIntPtr 
long*Oout long

API与C#的数据类型对应关系表
API数据类型类型描述C#类型API数据类型类型描述C#类型
WORD16位无符号整数ushortCHAR字符char
LONG32位无符号整数intDWORDLONG64位长整数long
DWORD32位无符号整数uintHDC设备描述表句柄int
HANDLE句柄,32位整数intHGDIOBJGDI对象句柄int
UINT32位无符号整数uintHINSTANCE实例句柄int
BOOL32位布尔型整数boolHWM窗口句柄int
LPSTR指向字符的32位指针stringHPARAM32位消息参数int
LPCSTR指向常字符的32位指针StringLPARAM32位消息参数int
BYTE字节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[]转换为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#对应的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;
}


  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值