patterncsharpMinor
Data marshaling wrapper for a TCP server
Viewed 0 times
tcpmarshalingwrapperforserverdata
Problem
After a lot of research, I created this wrapper which I think fits very well to my needs. My project is a TCP server and I will be using this wrapper every time the server receives a packet. Basically, the wrapper will work marshaling raw
What do you think about this wrapper? Any hint on how I can improve it? I'm very concerned about performance.
Summing up, the wrapper have 3 methods:
byte[] into higher-level representation of the data as marshalable structs.What do you think about this wrapper? Any hint on how I can improve it? I'm very concerned about performance.
public static class MyMarshal
{
///
/// Marshals a raw buffer to a given marshalable struct.
///
public static unsafe T GetStructure(byte[] buffer) where T : struct
{
fixed (byte* bufferPin = buffer)
{
return (T)Marshal.PtrToStructure(new IntPtr(bufferPin), typeof(T));
}
}
///
/// Marshals a given T instance into a raw buffer.
///
public static unsafe byte[] GetBytes(T obj) where T : struct
{
byte[] rawBuffer = new byte[Marshal.SizeOf(obj)];
fixed (byte* rawBufferPin = rawBuffer)
{
Marshal.StructureToPtr(obj, new IntPtr(rawBufferPin), false);
}
return rawBuffer;
}
///
/// Crates a zero-initialized marshaled instance of T
///
public static unsafe T CreateEmpty() where T : struct
{
int typeSize = Marshal.SizeOf(typeof(T));
byte* rawBuffer = stackalloc byte[typeSize];
for (int i = 0; i < typeSize; i++)
rawBuffer[i] = 0;
T zeroInited = (T)Marshal.PtrToStructure(new IntPtr(rawBuffer), typeof(T));
return zeroInited;
}
}Summing up, the wrapper have 3 methods:
GetStructure(used right after I receive any valid packet to get the respective structure)
GetBytes(used when I want to send a packet to a client, converts a given struct value to a raw buffer to be send to the client)
CreateEmpty(used to create a zero-initialized instance of a given struct. This method is used when I have complex structures with no
Solution
The wrapper seems pretty good to me. The only change you might consider is that
and then:
Of course there's a tradeoff of an uncollectable memory for each type you call this with. And with anything performance-related, you'll need to measure to see if it delivers any benefit. The original code should be pretty fast so maybe it's not significant.
There shouldn't be any danger in no matter how often you call stackalloc, by definition it's not possible for any two such calls to affect the same stack at the same time. And there's no danger of any sort of recursion that would have more than 1 of these allocations on the same stack since the block is freed at the end of this function.
CreateWrapper really only needs to run once for each type; since these are structs it can return copies of the same empty object each time. Something like this should work:static class EmptyHolder where T : struct
{
public static T EmptyInstance;
// assign EmptyInstance in static constructor
}and then:
public static unsafe T CreateEmpty() where T : struct
{
return EmptyHolder.EmptyInstance;
}Of course there's a tradeoff of an uncollectable memory for each type you call this with. And with anything performance-related, you'll need to measure to see if it delivers any benefit. The original code should be pretty fast so maybe it's not significant.
There shouldn't be any danger in no matter how often you call stackalloc, by definition it's not possible for any two such calls to affect the same stack at the same time. And there's no danger of any sort of recursion that would have more than 1 of these allocations on the same stack since the block is freed at the end of this function.
Code Snippets
static class EmptyHolder<T> where T : struct
{
public static T EmptyInstance;
// assign EmptyInstance in static constructor
}public static unsafe T CreateEmpty<T>() where T : struct
{
return EmptyHolder<T>.EmptyInstance;
}Context
StackExchange Code Review Q#125719, answer score: 2
Revisions (0)
No revisions yet.