笔者在改进某嵌入式收费系统时,从C的指针开始着手,总结到一些关于嵌入式客户端和基于.net 的服务端交换数据的方法!或许对大家有一定用处,因此奉献上来。
在公司自己修改的Linux 嵌入式系统里写软件目前我们用C来交叉编译出 核心板上运行的程序,涉及到和服务器的数据交换, 一般而言客户端使用结构,然后将该结构内存中的内容发送到服务端,假如是C++,一切好办,因为它和c大差不差,c能办到他也能办到,但是.Net 却很繁重。难道用c++写一个中间程序?麻烦!!!写一个字符串拆分或者二进制的拆分?。。。
究竟如何使用.Net简易而且又方便的序列化和反序列化数据,使得客户端和服务器端沟通比较简单呢?请看下面:
首先,我们需要一个 序列化和反序列化程序,以及 一个结构。
结构如下:
Code
/// <summary>
///表名称PLAZA,字段数目4
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct MSG_PLAZA
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] NetWork;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
public byte[] PLAZA;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] PLAZANAME;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
public byte[] NetWorkName;
}//PLAZA
注意,您定义的结构必须按照上面的方式去定义。 以便序列化和反序列化。
下面说明如何序列化和反序列化:
Code
public override string ToString()
{
int rawsize = Marshal.SizeOf(_MSG_PLAZA);//得到内存大小
IntPtr buffer = Marshal.AllocHGlobal(rawsize);//给指针分配内存
Marshal.StructureToPtr(_MSG_PLAZA, buffer, true);//_MSG_PLAZA(事先声明好的)中的内容转换为结构为指针
byte[] rawdatas = new byte[rawsize];//定义一个结构大小的字节数组
Marshal.Copy(buffer, rawdatas, 0, rawsize);//拷贝指针中的内容到这个字节数组中
Marshal.FreeHGlobal(buffer); //释放内存 切勿忘记
return Encoding.GetEncoding(936).GetString(rawdatas);转换为字符串。
}
public void Parse(string s)
{
Type anytype = typeof(MSG_PLAZA);//取得结构的类型,用于获得其大小
byte[] rawdatas = Encoding.GetEncoding(936).GetBytes(s);//将字符串使用自定的编码转换为 二进制
int rawsize = Marshal.SizeOf(anytype);//获得这个结构的内存大小
if (rawsize > rawdatas.Length)
_MSG_PLAZA = new MSG_PLAZA();
IntPtr buffer = Marshal.AllocHGlobal(rawsize);//分配一个指针并制定大小
Marshal.Copy(rawdatas, 0, buffer, rawsize);//将刚才由字符串转换的二进制福至今这个指针当中,一定注意大小否则会有异常,
object retobj = Marshal.PtrToStructure(buffer, anytype);//将这个指针转换为指定Type的对象。
Marshal.FreeHGlobal(buffer);//释放刚才的指针,一定要释放,否则时间长了会内存暴涨!笔者在公司的产品中忘掉了一个结构的释放函数,导致程序运行一个月后崩溃。
_MSG_PLAZA = (MSG_PLAZA)retobj;//转换为制定对象的结构(_MSG_PLAZA 是事先声明了的)
}
到这里你为疑惑,那如何访问 二进制的结构呢。 时间类型 int类型 字符串 类型 和 这个二进制结构中的元素如何转换呢?
Code
[DataField("PLAZANAME")]
public string PLAZANAME
{
get
{
return Encoding.GetEncoding(936).GetString(_MSG_PLAZA.PLAZANAME);// 将这个字段转换为字符串。 转换为字符串后,即便是int 还是日期格式,都是可以转换的!这个就不用在这里讨论了吧。 下面的set中也是如此,任何值都可以转换为字符串。
}
set
{
_MSG_PLAZA.PLAZANAME = Encoding.GetEncoding(936).GetBytes(value.PadRight(20, ' '));//这里的20是这个_MSG_PLAZA.PLAZANAME 的长度。这句话的意思是将值转换为二进制,且如果不够这个字段的长度,使用空格右补齐
}
}
即便如此, 每次总是需要调用个ToString 和 Pase之类的函数, 还是不爽,那么请看下面的方法:
Code
MSG_PLAZA _MSG_PLAZA;
public PLAZA(MSG_PLAZA ___MSG_PLAZA)
{
_MSG_PLAZA = ___MSG_PLAZA;//根据结构来实例化一个类
}
public PLAZA()
{
Parse("".PadRight(GetLenght(), ' '));使用空格实例化一个类
}
public PLAZA(string s)//使用制定字符串实例化一个类
{
Parse(s);//调用Pase 将字符串反序列化到_MSG_PLAZA
}
public int GetLenght()
{
return Marshal.SizeOf(_MSG_PLAZA); 取得这个结构的大小
}
//由一个string隐式构造一个PLAZA 使用方法:PLAZA _PLAZA ="字符串字符串";
public static implicit operator PLAZA(string s)
{
return new PLAZA(s);// }
//由一个PLAZA显式返回一个string 使用方法: string strPlaza=_PLAZA ;
public static explicit operator string(PLAZA ret)
{
return ret.ToString();//
}
实现您的c中的结构必须和c#的结构相同。且大小相同。
至于如何在c中将结构转换为字符串 和 字符串转换为结构 我想不必多言了吧!对这篇文章感兴趣的,肯定也是有类似应用的,因此对c也肯定有了解。