我正在开发一个通过µController
与UDP-Messages
进行通信的图书馆。为此,我使用的是一个自定义协议,它基本上是一个由2个元素组成的结构:标题(一些元数据+校验和)和有效负载。
通过System.Net.Sockets.UDPClient
类完成通信。要转换我的数据,我使用以下函数:
private List<byte> GetBytes(object str)
{
int size = Marshal.SizeOf(str);
byte[] arr = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(str, ptr, true);
Marshal.Copy(ptr, arr, 0, size);
Marshal.FreeHGlobal(ptr);
return arr.ToList();
}
如果我想发送一些不是常量大小的有效负载,我现在遇到问题,例如,如果我只想向μController写一些可变长度的数据。我目前使用的一种解决方法是将我的有效负载封装在一个常量(最大)大小的结构中,但这对我来说似乎不是很有效。
那么,有没有办法将非常量大小的结构转换为带有C#的字节数组?例如这个结构:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct PERIPHERY__PROTOCOL
{
public PERIPHERY_HEADER strHeader;
public byte[] Data;
}
答案 0 :(得分:1)
在您的PERIPHERY__PROTOCOL
示例中,您实际上并未将数据放入结构中 - 您正在创建单独的数组并将数据放在那里。你仍然可以做到这一点,绝对 - 但你必须支付堆开销。在这种情况下,忘记Marshal
- 您只需传递 arr
到结构。
但如果你的意思是“我可以在.NET中使用可变长度的结构”;不 - 不,你不能。
答案 1 :(得分:1)
为什么要使用结构?
使用课程。此示例代码允许您添加新的数据包类型并将其转换为字节。如果你想要将它转换回来的机制(从字节到类),你需要添加自己的发明。
public abstract class Packet
{
public int PacketType { get; }
public Packet (int packetType)
{
PacketType = packetType;
}
protected abstract byte[] GetPayload ();
private int CalculateChecksum ()
{
byte[] packetTypeBytes = BitConverter.GetBytes (PacketType);
byte[] payloadBytes = GetPayload ();
byte[] lengthBytes = BitConverter.GetBytes (payloadBytes.Length);
return 0; // add some logic to calculate checksum from all bytes
}
public byte[] ToBytes ()
{
byte[] packetTypeBytes = BitConverter.GetBytes (PacketType);
byte[] checksumBytes = BitConverter.GetBytes (CalculateChecksum ());
byte[] payloadBytes = GetPayload ();
byte[] lengthBytes = BitConverter.GetBytes (payloadBytes.Length);
return packetTypeBytes.Concat (lengthBytes).Concat (checksumBytes).Concat (payloadBytes).ToArray ();
}
}
public sealed class ActionA : Packet
{
public string Message { get; }
public ActionA (string message) : base (0)
{
Message = message;
}
protected override byte[] GetPayload ()
{
return Encoding.ASCII.GetBytes (Message);
}
}
public sealed class ActionB : Packet
{
public int Value { get; }
public ActionB (int value) : base (1)
{
Value = value;
}
protected override byte[] GetPayload ()
{
return BitConverter.GetBytes (Value);
}
}