Your comments please on Marshal.PtrToStructure(..) ...

  • Thread starter Thread starter GeorgeG
  • Start date Start date
G

GeorgeG

Hi,

I have the following code (which works fine) to quickly deblock incoming
stream of data from sockets.
What do you think? Do you see any performance problems using interop for
such a thing?
Reminds me casting a stream of bytes to a struct in C/C++.

many thanks in advance
GeorgeG


########################### code sample starts here
###########################################

[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public unsafe struct myData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
public byte[] data1;
[MarshalAs(UnmanagedType.U1, SizeConst=1)]
public byte data2;
[MarshalAs(UnmanagedType.U1, SizeConst=1)]
public byte data3;

// byte [] data : contains the data to be deserialized.
// out myData d : ref to a struct to be rehydrated with data (works fine as
a non-static method aswell).
public static unsafe void Deserialize( byte [] data, out myData d)
{
fixed ( byte * p_data = data)
{
System.IntPtr ptr = new IntPtr(p_data);
ctfTrailer = (myData)Marshal.PtrToStructure(ptr,
typeof(myData));
}
}
}
########################### code sample ends here
###########################################
 
George,
What do you think? Do you see any performance problems using interop for
such a thing?

I don't like to guess about performance issues, better measure it.

Personally, I'd probably use the BitConverter class (or even manual
shifting of bytes) for such a small amount of data.



Mattias
 
That was just a small sample of a stuct. If could be done for much bigger
structs. The question is if its ok to use something like this under managed
code and with no direct need of interop.

GeorgeG.
 
The question is if its ok to use something like this under managed
code and with no direct need of interop.

Well you should probably avoid it if you want your code to run in a
partially trusted context.



Mattias
 
I dont really mind that.

My main aim with it is to have very simple code for deblocking/building
messages. I have been using it for a few days now and I had no problems with
it.

So its only a matter of being a "good practice" or not, that is having an
unsafe block in an managed env just for the shake of "easily" deblocking
messages..

G.
 
You can avoid the double copy each time by casting a struct on the returned
byte[] or pointer to it. You need to observe certain rules for the struct
(like blittable types), but it can be faster if you don't actually need to
create an object (i.e. checking byte[]) and is faster then using bit
converter on each field. I can't remember, but you may not be able to do
casting with the data1 byte[2]. If you change it to a short or ushort, it
should work I think.
The idea is:

[StructLayout(LayoutKind.Explicit)]
private struct DnsHeader
{
[FieldOffset(0)] internal ushort id; // Header ID
[FieldOffset(2)] internal byte firstByte; // First byte with qr, opcode,
etc
[FieldOffset(3)] internal byte secondByte; // Second byte with ra,z,rcode
[FieldOffset(4)] internal ushort qdCount; // Question Count
[FieldOffset(6)] internal ushort anCount; // Answer Count
[FieldOffset(8)] internal ushort nsCount; // NS Count
[FieldOffset(10)] internal ushort arCount; // Additional Count
}

unsafe public Header(byte[] message, ref int msgIndex) : this()
{
fixed(byte *fixedBuf = message) //fix message byte array
{
DnsHeader * header = (DnsHeader *)fixedBuf;

//Parse ID
id = header->id;
id = (ushort)IPAddress.NetworkToHostOrder((short)id);

//Parse QR
firstByte = header->firstByte;
secondByte = header->secondByte;
qr = (firstByte & 0x80) == 0x80;
....
 
Many thanks for your replies,



William Stacey said:
You can avoid the double copy each time by casting a struct on the returned
byte[] or pointer to it. You need to observe certain rules for the struct
(like blittable types), but it can be faster if you don't actually need to
create an object (i.e. checking byte[]) and is faster then using bit
converter on each field. I can't remember, but you may not be able to do
casting with the data1 byte[2]. If you change it to a short or ushort, it
should work I think.
The idea is:

[StructLayout(LayoutKind.Explicit)]
private struct DnsHeader
{
[FieldOffset(0)] internal ushort id; // Header ID
[FieldOffset(2)] internal byte firstByte; // First byte with qr, opcode,
etc
[FieldOffset(3)] internal byte secondByte; // Second byte with ra,z,rcode
[FieldOffset(4)] internal ushort qdCount; // Question Count
[FieldOffset(6)] internal ushort anCount; // Answer Count
[FieldOffset(8)] internal ushort nsCount; // NS Count
[FieldOffset(10)] internal ushort arCount; // Additional Count
}

unsafe public Header(byte[] message, ref int msgIndex) : this()
{
fixed(byte *fixedBuf = message) //fix message byte array
{
DnsHeader * header = (DnsHeader *)fixedBuf;

//Parse ID
id = header->id;
id = (ushort)IPAddress.NetworkToHostOrder((short)id);

//Parse QR
firstByte = header->firstByte;
secondByte = header->secondByte;
qr = (firstByte & 0x80) == 0x80;
...

--
William Stacey, MVP

GeorgeG said:
Hi,

I have the following code (which works fine) to quickly deblock incoming
stream of data from sockets.
What do you think? Do you see any performance problems using interop for
such a thing?
Reminds me casting a stream of bytes to a struct in C/C++.

many thanks in advance
GeorgeG


########################### code sample starts here
###########################################

[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public unsafe struct myData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst=2)]
public byte[] data1;
[MarshalAs(UnmanagedType.U1, SizeConst=1)]
public byte data2;
[MarshalAs(UnmanagedType.U1, SizeConst=1)]
public byte data3;

// byte [] data : contains the data to be deserialized.
// out myData d : ref to a struct to be rehydrated with data (works fine as
a non-static method aswell).
public static unsafe void Deserialize( byte [] data, out myData d)
{
fixed ( byte * p_data = data)
{
System.IntPtr ptr = new IntPtr(p_data);
ctfTrailer = (myData)Marshal.PtrToStructure(ptr,
typeof(myData));
}
}
}
########################### code sample ends here
###########################################
 
Back
Top