Marshalling your data for Socket/IO? Maybe not.

By April 4, 2017Programming

Hi again!  Today I’ve been working on send variable sized data packets over from my client to server using the simple TCP components I mentioned in this post <link here>.

I have a few different classes that I want to serialize to byte[]s and send over the wire.   After reading a few suggestions online, I decided to try Marshalling.

With marshaling, you can copy the bytes as they are stored in memory – which is exactly what I needed.

 

            //Serialize data

            int size = Marshal.SizeOf(data);

            byte[] dataArr = new byte[size];

            IntPtr ptr = Marshal.AllocHGlobal(size);

            Marshal.StructureToPtr(data, ptr, false);

            Marshal.Copy(ptr, dataArr, 0, size);

            Marshal.FreeHGlobal(ptr);

This copies the byte[] into dataArr.

Here’s Microsoft’s documentation

https://msdn.microsoft.com/en-us/library/system.runtime.interopservices.marshal(v=vs.110).aspx

 

The only caveat with Marshalling is that you have to explicitly define the size of each property in your class.  And as I mentioned earlier, I was sending variable sized data packets.  Sometimes the property of my class would be quite large (ie. 500Kb) and other times really small (ie. 128 bytes).

[StructLayout(LayoutKind.Sequential, Pack = 1,CharSet = CharSet.Ansi)]
    public class HtsSenderPacket
    {  
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 300000)]
        public byte[] ScreenCapture;
        public HtsSenderPacket()
        {
            ScreenCapture = new byte[300000];
        }
    }


So I defined my ScreenCapture property to be a very large byte[].  I didn’t fill it all most of the time, but  I still was forced to send 300000 bytes.  So marshalling isn’t really the way to go for this case.  However, if you do decide to go this route, be sure to include the attribute:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 300000)]

I forgot this at first and was only sending the address and not the value.

Since marshalling wasn’t going to work for me, I ended up writing my class where I include the size of the variable property.

public class HtsPacket

{  
        private byte[] _screenCaptureSize = new byte[32];
        private byte[] _screenCapture; //variable size

        private int CLASS_SIZE { get { return 32 + _screenCapture.Length; } }
        public byte[] ScreenCapture { get { return _screenCapture; } }

        public HtsPacket(){
        }

        public HtsPacket(byte[] screenCapture){
          _screenCaptureSize = HtsEncoding.GetBytes(screenCapture.Length);
          _screenCapture = screenCapture;
        }    

        public byte[] ToBytes(){ //Serializes class to bytes        
            byte[] arr = new byte[CLASS_SIZE];
            Array.Copy(_screenCaptureSize, 0, arr, 0, _screenCaptureSize.Length);
            Array.Copy(_screenCapture, 0, arr, 32, _screenCapture.Length);
            return arr;
        }
    }

Comments

comments