0

I'm working on a library that communicated with a µController via UDP-Messages. For that I'm using a custom protocol which is basically a struct consisting of 2 elements: The header (some metadata + checksum) and the payload. The communication is done via the System.Net.Sockets.UDPClient Class. To convert my data I'm using the following function:

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();
}

I'm running into problems now if I want to send some payload which is not of a constant size, for example if I just want to write some data of variable length to the µController. One workaround that I am currently using is to just encapsulate my payload in a struct of a constant (maximum) size, but that seems not very efficient to me.

So, is there any way to convert a struct of a non constant-size to a Byte-Array with C#? For example this struct:

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct PERIPHERY__PROTOCOL
{
    public PERIPHERY_HEADER strHeader;       
    public byte[] Data;
}
Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
kain
  • 129
  • 1
  • 7
  • Possible duplicate of [How to convert a structure to a byte array in C#?](http://stackoverflow.com/questions/3278827/how-to-convert-a-structure-to-a-byte-array-in-c) – KillerIsDead May 18 '17 at 13:31
  • @KillerIsDead I don't think that addresses the key part of the issue here – Marc Gravell May 18 '17 at 13:33
  • Note that *in your code*, you are allocating some unmanaged memory, writing to it, then releasing the unmanaged memory - that... isn't actually very useful to anything – Marc Gravell May 18 '17 at 13:34

2 Answers2

1

In your PERIPHERY__PROTOCOL example, you aren't actually putting the data into the struct - you are creating a separate array and putting the data there. You can still do that, absolutely - but you'll have to pay the heap overheads. In that case, forget about Marshal - you'd just pass arr to the struct.

But if you mean "can I have variable length structs in .NET"; no - no you cannot.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

Why you want to use a struct?

Use a class. This sample code lets you add new packet types and convert them to bytes. If you want mechanism which will convert it back (from bytes to classes), you need to add your own invention.

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);
    }
}
apocalypse
  • 5,764
  • 9
  • 47
  • 95
  • The C Code that runs on the µController uses structs. I just copied and adapted them to my C# library – kain May 18 '17 at 14:17
  • @kain: Forget about C code on controller side. Just send valid data. If you use C#, program like in C#, not like in C. – apocalypse May 18 '17 at 14:25