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#类型
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 语言类型

 

 

托管类名

 

 

说明

 

 

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/archive/2010/05/20/struct.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值