Monday, September 17, 2007

Marshaling structures over TCP/IP

[this post came from our old blog]
To create a distributed application you can use TCP/IP, Remoting, Web Services, WSE etc.
There are 2 benefits with TCP/IP:
Performance Connecting .net application to legacy applicationsWhen you use for example a TCP server written in C on of the problems is to marshal structures.
.NET socket class provides a Receive method that fills a byte buffer.
The only problem is to convert it to the structure

Some ways I know:

Option 1: Using MemoryStream and BinaryReader (field by field)
C struct:
struct Demo{
int x;
int y;
};

C#
class Demo
{
public int x;
public int y;
}

Socket s = tcpl.AcceptSocket();
byte[] buf = new byte [100];

int bytesReceived = s.Receive(buf);
Demo d = new Demo();
MemoryStream m = new MemoryStream(buf);
BinaryReader br = new BinaryReader(m);
d.x = br.ReadInt32();
d.y = br.ReadInt32();


Option 2: using unsafe code (field by field)
You have to compile with /unsafe option and your code is not secured but its faster

unsafe
{
fixed (byte * p1 = buf)
{
int* p = (int *)p1;
d.x = *p;
d.y = *(p + 1);
}
}

Option 3: using Marshal class (all at once)
Its easy because you Marshal the structure at one time but its very inefficient (marshaling to the unmanaged heap and back to the managed heap)

[StructLayout(LayoutKind.Sequential)]
class Demo
{
public int x;
public int y;
}
......

Socket s = tcpl.AcceptSocket();
byte[] buf = new byte [100];

int bytesReceived = s.Receive(buf);
Demo d = new Demo();
IntPtr p1 = Marshal.AllocCoTaskMem( Marshal.SizeOf(typeof(Demo)));
Marshal.Copy(buf, 0, p1, Marshal.SizeOf(typeof(Demo)));
Marshal.PtrToStructure(p1, d);
Marshal.FreeCoTaskMem(p1);

option 4: using struct

if you declare it as struct (with all its constrains)
unsafe {
fixed (byte* p1 = buf) {
Demo* p = (Demo *)p1;
d = *p;
}
}

for help and other learning materials
visit our site: Bina

No comments: