C++中,我们可以非常方便的将网络通讯接收来的char*缓冲区转成任意类型的结构体,并从中提取必要信息,只需要一个结构体类型指针的强制转换即可。

但是在C#中,所有涉及到内存及指针的操作均被判定为不安全操作,使得上述机制的实现变得复杂化。

要在C#中便捷的实现网络通讯缓冲区byte[]与任意类型对象的相互转换,常用的方法大致有三:

1.序列化与反序列化

public static byte[] ObjectToBytes(object obj) { using (MemoryStream ms = new MemoryStream()) { IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.GetBuffer(); } } public static object BytesToObject(byte[] Bytes) { using (MemoryStream ms = new MemoryStream(Bytes)) { IFormatter formatter = new BinaryFormatter(); return formatter.Deserialize(ms); } }

注意:传入的结构体类型一定是“可序列化的(Serializable)”

优点:安全可靠

使用这种方法一般不会产生其他的副作用,其安全度在C#的可控范围之内。

缺点:浪费资源、效率偏低

使用这种方法会造成不必要的资源浪费:

struct原有大小 序列化之后的byte[]大小
100                   256
800                   1024
1000                 2048
3000                 4096
6000                 8192
10000               16384
产生出不必要的冗余数据,效率的降低将是必然结果。
2.内存流配合BitConvert
BitConvert类提供了丰富的byte[]与其他基础类型(Int16、Int32等)间的互换方法。
byte[]转成特定struct时,需要实现new一个新的struct。之后借助BitConvert将接收来的byte[]缓冲区特定段按照struct各部分定义转化为相应类型,并赋值给struct成员。反之亦然。
优点:安全可靠,性能可观

使用这种方法一般不会产生其他的副作用,其安全度在C#的可控范围之内。

缺点:资源浪费,不易实现

使用这种方法造成了额外的内存申请与复制。

另外,针对每种特定类型的数据包,需要提供特定的包解析与生成机制。

可以考虑通过包类型间的继承关系降低后期维护的难度。比如:定义一种基类型的数据包,子类数据包继承基类数据包的成员,并重写基类的解析与生成方法等等。

3.Marshal

该类对外提供了一个方法集,这些方法用于分配非托管内存、复制非托管内存块、将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法。

public static byte[] StructToBytes(Object obj) { int size = Marshal.SizeOf(obj); byte[] bytes = new byte[size]; IntPtr arrPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0); Marshal.StructureToPtr(obj, arrPtr, true); return bytes; } public static Object BytesToStruct(byte[] bytes,Type StructStyle) { IntPtr arrPtr = Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0); return Marshal.PtrToStructure(arrPtr, StructStyle); }

.net 4.0 实现方法:

        /// <summary>
/// 由结构体转换为byte数组
/// </summary>
public static byte[] StructureToByte<T>(T structure)
{
int size = Marshal.SizeOf(typeof(T));
byte[] buffer = new byte[size];
IntPtr bufferIntPtr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(structure, bufferIntPtr, true);
Marshal.Copy(bufferIntPtr, buffer, 0, size);
}
finally
{
Marshal.FreeHGlobal(bufferIntPtr);
}
return buffer;
}
/// <summary>
/// 由byte数组转换为结构体
/// </summary>
public static T ByteToStructure<T>(byte[] dataBuffer)
{
object structure = null;
int size = Marshal.SizeOf(typeof(T));
IntPtr allocIntPtr = Marshal.AllocHGlobal(size);
try
{
Marshal.Copy(dataBuffer, 0, allocIntPtr, size);
structure = Marshal.PtrToStructure(allocIntPtr, typeof(T));
}
finally
{
Marshal.FreeHGlobal(allocIntPtr);
}
return (T)structure;
}

优点:高效、易实现

这个方法的实际效果与C++类似,不存在额外的内存申请及拷贝动作。

缺点:不安全、功能受限

1> 某些特殊情况下,该方法会失效。

2> 由于涉及到了与非托管内存间的转换,安全度降低。

3> C#中的Struct功能弱化,无法有效组织数据包继承关系。

4> 在一些特有环境下,Marshal的权限并未全部公开,比如Silverlight。

相关参考:http://www.cnblogs.com/JLL/archive/2005/07/23/198851.html

http://pierce.cnblogs.com/archive/2005/06/21/178343.aspx

C#中实现byte[]与任意对象互换(服务端通讯专用)相关推荐

  1. android post json格式,Android中post请求传递json数据给服务端的实例

    在最近的项目中有个需求是这样的: 入参封装成JSON,EXAMPLE: { "uuid": "iamauuid","clientType": ...

  2. android json传输数据到服务器,Android中post请求传递json数据给服务端的实例

    在最近的项目中有个需求是这样的: 入参封装成JSON,EXAMPLE: { "uuid": "iamauuid", "clientType" ...

  3. wml在文本框中输入中文关键字搜索时,服务端获取到的值总是乱码的解决方法。...

    wml在文本框中输入中文关键字搜索时,服务端获取到的值总是乱码,该如何解决? 现提供一个客户端对关键字编码,服务端再解析的方法,应该可以完美的解决这一问题. wml文件: <?xml versi ...

  4. jQuery中的ajax、jquery中ajax全局事件、load实现页面无刷新局部加载、ajax跨域请求jsonp、利用formData对象向服务端异步发送二进制数据,表单序列化(异步获取表单内容)

    jQuery中使用ajax: 在jQuery中使用ajax首先需要引入jQuery包,其引入方式可以采用网络资源,也可以下载包到项目文件中,这里推荐下载包到文件中:市面上有多个版本的jQuery库,这 ...

  5. linux中UDP程序流程、客户端、服务端

    UDP--- 用户数据报协议(User Datagram Protocol),是一个无连接的简单的面向数据报的运输层协议. 优点:传输速度快 缺点:不可靠 socket的中文意思是接插件: 创建soc ...

  6. Ajax 实现在WebForm中拖动控件并即时在服务端保存状态数据 (Asp.net 2.0)(示例代码下载)...

    (一) . 运行示例效果 * 运行后用鼠标拖动蓝色的<马>到任意位置, 将浏览器关闭后, 再重新访问本页面, 会发现<马>仍然在您拖到的位置 (二). AjaxPro.NET简 ...

  7. php中接口验证失败,支付宝手机接口,服务端PHP验证失败,求助

    本帖最后由 js14654952 于 2013-01-16 17:12:11 编辑 最近做支付宝手机接口郁闷死了 求大神们帮忙~! 问题1:手机端安卓自然是JAVA,而服务端是PHP,在做支付宝异步验 ...

  8. 阿里云对象存储服务OSS前后联调

    阿里云对象存储服务OSS前后联调 1.为什么要引入阿里云对象存储服务(OSS)?有什么好处? 1.1.什么是对象存储OSS 1.2.OSS工作原理 2.阿里云对象存储-普通上传方式 2.1.时序图 2 ...

  9. android studio中使用AIDL进行客户端与服务端互相通信

    前言 在AIDL实现IPC通信,调用远程服务端的方法.但是,远程服务端并不能主动给客户端返回信息.在很多情况下是需要远程服务端主动给客户端返回数据,客户端只需要进行监听即可,这是典型的观察者模式.这篇 ...

最新文章

  1. linux 下/proc/cpuinfo三级缓存,linux /proc/cpuinfo文件分析
  2. python中datetime模块常用方法_Python中datetime的使用和常用时间处理
  3. 定义一个dto对象_正确理解DTO、值对象和POCO
  4. 【算法】深度优先搜索遍历的应用 设计算法以求解无向图G的连通分量的个数和无向图G的边数
  5. 【ThinkingInC++】61、非成员运算符
  6. memcached和redis的区别
  7. Github管理Eclipse分布式项目
  8. 垃圾收集算法,垃圾收集器_为什么我不能关闭垃圾收集器?
  9. pat根据中序遍历和先序遍历_[leetcode/lintcode 题解] 前序遍历和中序遍历树构造二叉树...
  10. Vim 实用技术,第 2 部分: 常用插件(转)
  11. 特征点检测-SIFT
  12. matlab魔方矩阵有哪些,关于matlab 魔方矩阵的1、用前100个自然数创建一个10阶的魔方矩阵,求出每行、每列、所有对角线元素的和,再将矩阵...
  13. python登录判断用户名和密码_第一个python程序-判断登陆用户名和密码是否正确...
  14. 递归回溯生成和解决数独问题c/c++
  15. 英文字母字符简便替换法
  16. Android定制属于你自己的导航栏
  17. 不吸电子烟也请别吸电子咖啡!我们向雪加电子咖啡发起了挑战
  18. [C#] 使用 NAudio 实现音频可视化
  19. 自动驾驶路径规划:A*(Astar)算法
  20. ThinkPhp学习笔记——创建数据数据库中的表单

热门文章

  1. uvm 形式验证_6.小白学uvm验证 - 寄存器模型
  2. jira confluence 作用 ppt_有没有一个PPT技巧让自己觉得人生都亮了?
  3. DHCP配置 TFTP服务
  4. 使用sqlyog链接多个主机的数据库
  5. Linux知识--初始linux
  6. LindDotNetCore~入门基础
  7. Apache阶段二-
  8. VS2017 15.4提供预览版,面向Windows 10秋季更新(FCU)
  9. 第六章 输入输出系统-作业
  10. 华为手表表盘的数字什么意思_手表的陀飞轮、月相、逆跳都是什么意思?