首页 > 编程语言 >C#中实现byte[]与任意对象互换(服务端通讯专用)

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

时间:2023-01-05 14:00:38浏览次数:40  
标签:return C# static new byte Marshal 服务端 size


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。

 


标签:return,C#,static,new,byte,Marshal,服务端,size
From: https://blog.51cto.com/kenkao/5991046

相关文章

  • 记 对接拼多多官方代报 辽宁电子口岸联达通客户端 ic卡加签版
    对接前准备详见pdd文档https://open.pinduoduo.com/application/document/browse?idStr=EE386BF9BCC6EEC1总结需要我们做的有1 实现我们持有ic卡机器上的加签接口功能......
  • Amber22 安装过程miniconda报错处理
    最近在安装amber22时,使用其官方说明安装,但在安装miniconda这一步出错,致使amber22安装不成功!报错如下:CondaFileIOError:'/home/lbm/amber22/amber22_src/build/CMakeFi......
  • 【web】Emscripten一些注意事项
    中文网址https://cntofu.com/book/150/zh/ch1-quick-guide/ch1-01-install.md编译选项-sSAFE_HEAP=1可以检测到内存未对齐的错误,但是会影响性能,应该只在测试时使用-s......
  • linux服务器cup100%问题排查
    一、出现问题在发现公司门禁服务无法开门的第一时间,去线上服务器上查看了一下进程的运行情况,具体运行如下:   第一次在查看的时候发现并没有我需要的服务entrancegua......
  • RHEL/CentOS yum 源问题
    yum源问题1RHEL本地iso设置为源https://www.programminghunter.com/article/39032455888/创建挂载点[root@PC1home]#mkdir-p/media/cdrom进入/etc/yum.re......
  • CSS - 设置内边距padding,复合写法,内边距会影响盒子大小的问题
    1.设置内边距/*设置上内边距*/padding-top:20px;/*设置下内边距*/padding-bottom:20px;/*设置左内边距*/padding-left:20px;/*设置右内边距*/padding-right......
  • NC16611 [NOIP2009]最优贸易
    题目链接题目题目描述C国有n个大城市和m条道路,每条道路连接这n个城市中的某两个城市。任意两个城市之间最多只有一条道路直接相连。这m条道路中有一部分为单向通行的道......
  • profession computing -- ethic
      Equality,DiversityandComputing:ImplicitBiasandStereotypeThreatJusticeandDiscrimination      SurveillanceandPrivacy:  ......
  • c++ 查找目录下的子目录及文件
    c++读取指定目录下的所有目录名称+文件名称-远征i-博客园(cnblogs.com) 文件句柄的类型long如果不行试试longlong 另外:使用了批处理,这篇很好CMD批处理循环......
  • dart Socket and ServerSocket
    ServerSocketvoidmain()async{ServerSocketserverSocket=awaitServerSocket.bind("localhost",8888);serverSocket.listen((Socketclient){client......