所以我使用一个简单的DatagramSocket创建了一个我想发送的结构。
结构代码如下:
public struct MsgData
{
private readonly int _value;
private readonly string _descr;
public MsgData(string desc, int value)
{
_descr = desc;
_value = value;
}
public int GetValue()
{
return _value;
}
public string GetDescr()
{
return _descr;
}
}
我继续转换为像这样的字节数组:
public static byte[] GetBytes(MsgData message)
{
var size = Marshal.SizeOf(message);
var data = new byte[size];
System.IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(message, ptr, true);
Marshal.Copy(ptr, data, 0, size);
Marshal.FreeHGlobal(ptr);
return data;
}
并将其返回到MsgData结构,如下所示:
public static MsgData GetMessage(byte[] bytes)
{
var data = new MsgData();
var size = Marshal.SizeOf(data);
var ptr = Marshal.AllocHGlobal(size);
Marshal.Copy(bytes, 0, ptr, size);
data = Marshal.PtrToStructure<MsgData>(ptr);
Marshal.FreeHGlobal(ptr);
return data;
}
但是我得到了:
System.ArgumentOutOfRangeException: 'Requested range extends past the end of the array.'
尝试在线转换时:
Marshal.Copy(bytes, 0, ptr, size);
我现在要使用简单的Serialization instad,但我想知道为什么这不能按预期工作?
答案 0 :(得分:2)
您的代码存在一些问题,因此请让我解释一下您需要做些什么才能解决问题。
首先,您的结构具有针对快速内存访问进行了优化的布局。当将其编组为字节数组时,默认情况下,您将复制该内存布局。
您的Marshal.SizeOf(...)
来电反映了这一点。它总是返回16。怎么可能?你的字符串怎么能被编组到这16个字节内的东西,即使字符串远远超过16?
答案是它没有。相反,您将指向字符串对象的指针编组为字节。
16个字节是int的8个字节(4个用于int + 4用于填充以对齐8字节内存地址边界上的下一个值,我正在运行64位),然后8个字节用于字符串参考(地址)。
那么需要做什么?你需要用一些属性来装饰你的结构,告诉编组引擎如何处理它:
[StructLayout(LayoutKind.Sequential, Pack=0)]
public struct MsgData
{
[MarshalAs(UnmanagedType.I4)]
private readonly int _value;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]
private readonly string _descr;
... rest as you have it
完成此操作后,您将从Marshal.SizeOf(...)
获得此尺寸:68。
68 = int为4字节,字符串为64。
请注意,在编组时,动态调整大小的结果并不是那么容易处理,因此设置字符串的上限是目前的方法。
但是,对于您的问题有一个更简单的解决方案,使用.NET中内置的二进制序列化。
以下是Get*
方法的两个新版本,不需要您进行编组:
public static byte[] GetBytes(MsgData message)
{
using (var stream = new MemoryStream())
{
new BinaryFormatter().Serialize(stream, message);
return stream.ToArray();
}
}
public static MsgData GetMessage(byte[] bytes)
{
using (var stream = new MemoryStream(bytes))
{
return (MsgData)new BinaryFormatter().Deserialize(stream);
}
}
请注意,您需要将SerializableAttribute
应用于您的结构:
[Serializable]
public struct MsgData
{