liv2hak
liv2hak

Reputation: 14970

Chunking a message into smaller chunks in C#

I have a C# class to create a message.

    public class ExMessage
    {
        private UInt16 m_SendingId = 123;
        private byte m_control_byte_1;
        private enum destination_service : byte
        {
          serv_1 = 0x0,
          serv_2 = 0x1
        };
        private byte m_pd;
        private byte m_filler_bytes;
        private byte[] m_payload;

        public byte[] Payload
        {
            get
            {
                return m_payload;
            }
        }


        /// <summary>
        /// Constructor.
        /// </summary>
        public ExMessage(byte[] payload)
        {
            m_pd = 0x0;
            m_control_byte_1 = 0xA5;
            m_payload = payload;
            m_filler_bytes = 0xF;

        }

        protected void WriteBody(Stream stream)
        {
            stream.WriteByte(m_control_byte_1); 
            stream.WriteByte(0x0); 

            stream.WriteWordLittleEndian(m_SendingId); 
            stream.WriteByte((byte)destination_service.serv_2); 

            stream.WriteByte((byte)m_pd); // payload details

            stream.WriteByte((byte)m_payload.Length); //write the payload length

            var count = 0;
            while (count < m_payload.Length)  //copy over the actual payload.
            {
                stream.WriteByte((byte)m_payload[count]);
                count++;
            }

            var len = 48 - (5 + m_payload.Length);
            count = 0;
            while (count < len) //copy over spare bytes 0x3
            {
                stream.WriteByte(m_filler_bytes);
                count++;
            }
        }

        public byte[] ToBytes()
        {
            MemoryStream stream = new MemoryStream();
            WriteBody(stream);

            return stream.ToArray();
        }

I create the message as follows

 var Message = new ExMessage(Encoding.UTF8.GetBytes("HelloWorld"));

Now my usage scenario is as follows.

1) The protocol that I am using imposes a size restriction of 40 bytes on the payload. If the number of bytes in the payload that I am passing is greater than 40 bytes it should be split into two messages.

2) Is there a way for the constructor to return a list of ExMessage objects based on the size of the byte array that I pass into it.

3) If not, what is the best way to handle this scenario

Upvotes: 1

Views: 620

Answers (2)

Enigmativity
Enigmativity

Reputation: 117057

Here's how I would do it:

var size = 4;
var messages =
    Encoding.UTF8.GetBytes("HelloWorld") //48 65 6C 6C 6F 57 6F 72 6C 64
        .Select((b, i) => new { b, i }) // Enumerable of byte and index
        .GroupBy(x => x.i / size, x => x.b) // group by index divide by block size
        .Select(x => new ExMessage(x.ToArray())); // create messages

That gives me:

messages

You would implement it like this:

public class ExMessage
{
    private const int __size = 4;
    public static ExMessage[] Create(byte[] payload)
    {
        return payload
            .Select((b, i) => new { b, i })
              .GroupBy(x => x.i / __size, x => x.b)
              .Select(x => new ExMessage(x.ToArray()))
              .ToArray();
    }
    /* rest of class */
}

You'd then call it like this:

var messages = ExMessage.Create(Encoding.UTF8.GetBytes("HelloWorld"));

Upvotes: 3

user3188639
user3188639

Reputation:

No.

I'd use a static function on ExMessage, something like this:

class ExMessage
{
   ...
   public static List<ExMessage> CreateMessages(byte[] payload)
   {
      List<byte[]> chunks = ... split payload into 40byte chunks...
      return chunks.Select(p => new ExMessage(p).ToList();     
   }
   ...
}

Upvotes: 1

Related Questions