在C/S端编程的时候,经常要在C端和S端之间传数据时自定义一下报文的帧头,如果是在C/C++,封装帧头是一件很简单的事情,直接把unsigned char *强转为struct就行,但是在C#中,并没有提供直接从struct到byte[]的转换,这个时候就需要用到Marshal等非托管的方法了。
自定义帧
我们可以在C#中写出如下代码:
1 [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1,Size = 12)]
2 [Serializable()]
3 public struct DatagramHeaderFrame
4 {
5 // MessageType类型:
6 public MessageType MsgType;
7
8 //一个四个字节的特征码
9 public uint FeatureCode;
10
11 //用于标识报文的长度,用于校验
12 public int MessageLength;
13 }
首先我们说明一下,StructLayout是一个用于管理struct的布局特性,
CharSet指示在默认情况下是否应将类中的字符串数据字段作为 LPWSTR 或 LPSTR 进行封送处理;
Pack控制类或结构的数据字段在内存中的对齐方式。
Size指示类或结构的绝对大小。
LayoutKind是布局的类型,这个枚举有三个值:
Auto,运行库自动为非托管内存中的对象的成员选择适当的布局。 使用此枚举成员定义的对象不能在托管代码的外部公开。 尝试这样做将引发异常。
Explicit,在未管理内存中的每一个对象成员的精确位置是被显式控制的,服从于 StructLayoutAttribute. Pack 字段的设置。每个成员必须使用 FieldOffsetAttribute 指示该字段在类型中的位置。在MSDN文档中为我们展示了下面的一个例子:
1 [StructLayout(LayoutKind.Explicit)]
2 public struct Rect
3 {
4 [FieldOffset(0)] public int left;
5 [FieldOffset(4)] public int top;
6 [FieldOffset(8)] public int right;
7 [FieldOffset(12)] public int bottom;
8 }
Sequent