Socket Programming - How Do I Send and Receive a Class or Structure
-
In C++ you can do something like this: MyClass * myClass = new MyClass(a, b, c); ... ... mySocket->Send(myClass, sizeof(MyClass)); when receiving: BYTE buf[MAX_SIZE]; mySocket->Receive(&buf, sizeof(MyClass)); myClass = (MyClass *) &buf; In other words, given an instance of a class or structure you can send/receive it over tcp/ip as a binary object without having to do any special coding or serialization. How do I achieve the same thing in C#? I have a C++ based server that I want to communicate with using a C# front-end. The C++ server sends and receives structures. How can I convert a C# class or structure into raw bytes and send it over the network. The networking examples that I’ve been able to find all use strings, which are simple to convert to a series of bytes. I have not been able to find a single C# networking example that sends objects or structures over the network. Any help from someone who has solved this issue (without serialization) would be greatly appreciated. Thanks Robert
-
In C++ you can do something like this: MyClass * myClass = new MyClass(a, b, c); ... ... mySocket->Send(myClass, sizeof(MyClass)); when receiving: BYTE buf[MAX_SIZE]; mySocket->Receive(&buf, sizeof(MyClass)); myClass = (MyClass *) &buf; In other words, given an instance of a class or structure you can send/receive it over tcp/ip as a binary object without having to do any special coding or serialization. How do I achieve the same thing in C#? I have a C++ based server that I want to communicate with using a C# front-end. The C++ server sends and receives structures. How can I convert a C# class or structure into raw bytes and send it over the network. The networking examples that I’ve been able to find all use strings, which are simple to convert to a series of bytes. I have not been able to find a single C# networking example that sends objects or structures over the network. Any help from someone who has solved this issue (without serialization) would be greatly appreciated. Thanks Robert
With
Marshal.StructureToPtr
you can convert your managed object to an unmanaged block of memory.Marshal.ReadByte
can read the unmanaged object byte-by-byte into an array, so that you have a copy of the managed object in an array of bytes:IntPtr newPointer = Marshal.AllocHGlobal( Marshal.SizeOf(yourObject) ); Marshal.StructureToPtr( yourObject, newPointer, true ); byte[] b = new byte[Marshal.SizeOf(yourObject)]; for(int n=0; n
-
In C++ you can do something like this: MyClass * myClass = new MyClass(a, b, c); ... ... mySocket->Send(myClass, sizeof(MyClass)); when receiving: BYTE buf[MAX_SIZE]; mySocket->Receive(&buf, sizeof(MyClass)); myClass = (MyClass *) &buf; In other words, given an instance of a class or structure you can send/receive it over tcp/ip as a binary object without having to do any special coding or serialization. How do I achieve the same thing in C#? I have a C++ based server that I want to communicate with using a C# front-end. The C++ server sends and receives structures. How can I convert a C# class or structure into raw bytes and send it over the network. The networking examples that I’ve been able to find all use strings, which are simple to convert to a series of bytes. I have not been able to find a single C# networking example that sends objects or structures over the network. Any help from someone who has solved this issue (without serialization) would be greatly appreciated. Thanks Robert
I think you can do this in more than one way. Any way has it's pros and cons. One way would be using MS Messaging Queue to transport your object. Besides beeing a simple way without too much pain on thinking how to transmit it on the networking part, this requires to have the MSMQ services running. An other way is remoting. I haven't done much with remoting yet, so perhaps I may be wrong here. An other way would be to serialize the object (you can choose between XML or binary for example) and send the serialized object via TCP/IP and deserialize on the other machine. This includes a bit more work (serializing) and has the lower level transport. If the last part is already done, this might be a fast switch. [Sorry: I've overseen "without serialization", so forget the last possibility.] HTH, Sascha -- http://www.livingit.de http://www.mobile-bookmarks.info http://www.not2long.net
-
With
Marshal.StructureToPtr
you can convert your managed object to an unmanaged block of memory.Marshal.ReadByte
can read the unmanaged object byte-by-byte into an array, so that you have a copy of the managed object in an array of bytes:IntPtr newPointer = Marshal.AllocHGlobal( Marshal.SizeOf(yourObject) ); Marshal.StructureToPtr( yourObject, newPointer, true ); byte[] b = new byte[Marshal.SizeOf(yourObject)]; for(int n=0; n
Be careful when doing so, though. The managed class/struct must have exactly the same layout as your unmanaged class/struct. For classes and structures in .NET, you can use the
StructLayoutAttribute
to facilitate this when marshaling. Also pay close attention to unmanaged to managed types. For instance, a common mistake is that aLONG
in C++ would be along
in .NET. Not true. The former is a 32-bit integer where the latter is a 64-bit integer.Microsoft MVP, Visual C# My Articles
-
I think you can do this in more than one way. Any way has it's pros and cons. One way would be using MS Messaging Queue to transport your object. Besides beeing a simple way without too much pain on thinking how to transmit it on the networking part, this requires to have the MSMQ services running. An other way is remoting. I haven't done much with remoting yet, so perhaps I may be wrong here. An other way would be to serialize the object (you can choose between XML or binary for example) and send the serialized object via TCP/IP and deserialize on the other machine. This includes a bit more work (serializing) and has the lower level transport. If the last part is already done, this might be a fast switch. [Sorry: I've overseen "without serialization", so forget the last possibility.] HTH, Sascha -- http://www.livingit.de http://www.mobile-bookmarks.info http://www.not2long.net
Did you read his post? He doesn't want to use serialization because he's talking to a socket listener already written in C++ - a legacy solution. Remoting and a serialized graph over a socket connection are out. MSMQ is out because he's already using a socket listener. Should he decide to redo the server solution.
Microsoft MVP, Visual C# My Articles
-
Did you read his post? He doesn't want to use serialization because he's talking to a socket listener already written in C++ - a legacy solution. Remoting and a serialized graph over a socket connection are out. MSMQ is out because he's already using a socket listener. Should he decide to redo the server solution.
Microsoft MVP, Visual C# My Articles
Hi, have you read my edit of the post? I wrote I have just overseen the "without serialization", and just after I clicked 'Submit' I read this two words. Using the marshalling way is possible the best way for his problem. Bye, Sascha -- http://www.livingit.de http://www.mobile-bookmarks.info http://www.not2long.net
-
Be careful when doing so, though. The managed class/struct must have exactly the same layout as your unmanaged class/struct. For classes and structures in .NET, you can use the
StructLayoutAttribute
to facilitate this when marshaling. Also pay close attention to unmanaged to managed types. For instance, a common mistake is that aLONG
in C++ would be along
in .NET. Not true. The former is a 32-bit integer where the latter is a 64-bit integer.Microsoft MVP, Visual C# My Articles
Thanks for the advise folks. I am aware of the type differences between C++ and C#. So that would not be a problem for me. However, what about structure packing (i.e. #pragma pack(1))? Does StructLayoutAttribute ensure that the resulting structure in C# would be packed on the same boundaries as the C++ equivalent? How about passing classes between a C# client and a C# server, is Remoting the best choice or should I use the same technique as passing structures between C# and C++ clients and servers? I am most concerned about performance more than anything else because I am working on a stock trading application that needs to process huge amounts of streaming market data in real time.
-
Thanks for the advise folks. I am aware of the type differences between C++ and C#. So that would not be a problem for me. However, what about structure packing (i.e. #pragma pack(1))? Does StructLayoutAttribute ensure that the resulting structure in C# would be packed on the same boundaries as the C++ equivalent? How about passing classes between a C# client and a C# server, is Remoting the best choice or should I use the same technique as passing structures between C# and C++ clients and servers? I am most concerned about performance more than anything else because I am working on a stock trading application that needs to process huge amounts of streaming market data in real time.
Read the documentation for the
StructLayoutAttribute
. It does have aPack
property which allows you to control the packing. Remoting is basically serialization over transport channels and gives you the capability for aspect-oriented programming (inserting channel sinks to log calls, encrypt/decrypt messages, compress messages, and otherwise mangle messages). For talking to a legacy C++ socket listener, this wouldn't work. Remoting is best used between .NET applications but could - with a LOT of work - work between managed and unmanaged solutions. Web Services - for its greatly simplified interfaces - is better suited for legacy solutions. When it comes to performance, marshaling the class/struct to a buffer would definitely be faster. Remoting and Web Services both require serialization. The .NET FCL provides both SOAP and binary formatters for serialization, the latter of which is MUCH faster than the former and uses less bandwidth (since SOAP - being yet another grammar derived from XML - has a lot of overhead). Corinna's original idea I think is the right track, which is basically what you asked for.Microsoft MVP, Visual C# My Articles
-
Read the documentation for the
StructLayoutAttribute
. It does have aPack
property which allows you to control the packing. Remoting is basically serialization over transport channels and gives you the capability for aspect-oriented programming (inserting channel sinks to log calls, encrypt/decrypt messages, compress messages, and otherwise mangle messages). For talking to a legacy C++ socket listener, this wouldn't work. Remoting is best used between .NET applications but could - with a LOT of work - work between managed and unmanaged solutions. Web Services - for its greatly simplified interfaces - is better suited for legacy solutions. When it comes to performance, marshaling the class/struct to a buffer would definitely be faster. Remoting and Web Services both require serialization. The .NET FCL provides both SOAP and binary formatters for serialization, the latter of which is MUCH faster than the former and uses less bandwidth (since SOAP - being yet another grammar derived from XML - has a lot of overhead). Corinna's original idea I think is the right track, which is basically what you asked for.Microsoft MVP, Visual C# My Articles
-
I have tried this successfully. But only with a class and struct that does not contain a string or byte array field. For example: [StructLayout(LayoutKind.Sequential, Pack=1)] public struct MyPacket { public MyPacket(DateTime dateTime, int line, int msgLen) { dt = DateTime.Now; iLine = 0; iMsgLen = 0; msg = new byte[80]; } public DateTime dt; public int iLine; public int iMsgLen; public byte[] msg; } Marshal.Sizeof(MyPacket) returns 20. So when it is sent over the network I the contents of msg is lost. Obviously because byte[] is a reference to an array. So, now the question is how can I pass classes or structures as binary data if they contain arrays, for example a message that contains a stock quote needs to include a symbol name (i.e. "MSFT"). Can you help me out with this as well? I have not been able to find any examples or documentation that shows StructLayout being used with structures or classes that contain strings or arrays.
-
Read the documentation for the
StructLayoutAttribute
. It does have aPack
property which allows you to control the packing. Remoting is basically serialization over transport channels and gives you the capability for aspect-oriented programming (inserting channel sinks to log calls, encrypt/decrypt messages, compress messages, and otherwise mangle messages). For talking to a legacy C++ socket listener, this wouldn't work. Remoting is best used between .NET applications but could - with a LOT of work - work between managed and unmanaged solutions. Web Services - for its greatly simplified interfaces - is better suited for legacy solutions. When it comes to performance, marshaling the class/struct to a buffer would definitely be faster. Remoting and Web Services both require serialization. The .NET FCL provides both SOAP and binary formatters for serialization, the latter of which is MUCH faster than the former and uses less bandwidth (since SOAP - being yet another grammar derived from XML - has a lot of overhead). Corinna's original idea I think is the right track, which is basically what you asked for.Microsoft MVP, Visual C# My Articles
I have tried this successfully. But only with a class and struct that does not contain a string or byte array field. For example: [StructLayout(LayoutKind.Sequential, Pack=1)] public struct MyPacket { public MyPacket(DateTime dateTime, int line, int msgLen) { dt = DateTime.Now; iLine = 0; iMsgLen = 0; msg = new byte[80]; } public DateTime dt; public int iLine; public int iMsgLen; public byte[] msg; } Marshal.Sizeof(MyPacket) returns 20. So when it is sent over the network I the contents of msg is lost. Obviously because byte[] is a reference to an array. So, now the question is how can I pass classes or structures as binary data if they contain arrays, for example a message that contains a stock quote needs to include a symbol name (i.e. "MSFT"). Can you help me out with this as well? I have not been able to find any examples or documentation that shows StructLayout being used with structures or classes that contain strings or arrays. By the way, what does Microsoft MVP mean? Are you a Most Valuable Player at Microsoft? Thanks for the assistance, Robert G. Ellis
-
I have tried this successfully. But only with a class and struct that does not contain a string or byte array field. For example: [StructLayout(LayoutKind.Sequential, Pack=1)] public struct MyPacket { public MyPacket(DateTime dateTime, int line, int msgLen) { dt = DateTime.Now; iLine = 0; iMsgLen = 0; msg = new byte[80]; } public DateTime dt; public int iLine; public int iMsgLen; public byte[] msg; } Marshal.Sizeof(MyPacket) returns 20. So when it is sent over the network I the contents of msg is lost. Obviously because byte[] is a reference to an array. So, now the question is how can I pass classes or structures as binary data if they contain arrays, for example a message that contains a stock quote needs to include a symbol name (i.e. "MSFT"). Can you help me out with this as well? I have not been able to find any examples or documentation that shows StructLayout being used with structures or classes that contain strings or arrays. By the way, what does Microsoft MVP mean? Are you a Most Valuable Player at Microsoft? Thanks for the assistance, Robert G. Ellis
See the
MarshalAsAttribute
documentation. To make your implementation easier, usestring
instead ofbyte[]
but be sure to marshal it as an ANSI string (since you're obviously using bytes for chars and not double-byte chars):[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public struct Packet
{
public Packet(DateTime dt, int line, string msg)
{
if (msg == null) throw new ArgumentNullException("msg");this.dt = dt; this.line = line; this.msglen = msg.Length; this.msg = msg;
}
public DateTime dt;
public int line;
public int msglen;
[MarshalAs(UnmanagedType.LPStr)]public string msg;
}Now it's also possible that you may need to send a by-value string, in which case you use
UnmanagedType.ByValTStr
(it will be an ANSI string because of theCharSet
property in theStructLayoutAttribute
) and specify a constant size, which I know is often a valid limitation of chat software. This latter case is most likely what you'll need to do. Also, keep in mind that theDateTime
in .NET and whatever date/time struct/value you're using in C++ will most likely have different epochs. TheDateTime
struct uses 00:00:00 Jan 1, 0001 AD. Adjust your time as necessary. Often - depending on how your legacy solution is already coded, you should also useDateTime.ToUniversalTime
orDateTime.UtcNow
to use a UTC date which is based on zulu time (Greenwhich Mean Time). This ensures that your dates always have a common base. The clients use their locale information to get the local time. goodpilot wrote: By the way, what does Microsoft MVP mean? Are you a Most Valuable Player at Microsoft? It means "Most Valuable Professional". You can read more about the program at http://mvp.support.microsoft.com[^].Microsoft MVP, Visual C# My Articles
-
See the
MarshalAsAttribute
documentation. To make your implementation easier, usestring
instead ofbyte[]
but be sure to marshal it as an ANSI string (since you're obviously using bytes for chars and not double-byte chars):[StructLayout(LayoutKind.Sequential, Pack=1, CharSet=CharSet.Ansi)]
public struct Packet
{
public Packet(DateTime dt, int line, string msg)
{
if (msg == null) throw new ArgumentNullException("msg");this.dt = dt; this.line = line; this.msglen = msg.Length; this.msg = msg;
}
public DateTime dt;
public int line;
public int msglen;
[MarshalAs(UnmanagedType.LPStr)]public string msg;
}Now it's also possible that you may need to send a by-value string, in which case you use
UnmanagedType.ByValTStr
(it will be an ANSI string because of theCharSet
property in theStructLayoutAttribute
) and specify a constant size, which I know is often a valid limitation of chat software. This latter case is most likely what you'll need to do. Also, keep in mind that theDateTime
in .NET and whatever date/time struct/value you're using in C++ will most likely have different epochs. TheDateTime
struct uses 00:00:00 Jan 1, 0001 AD. Adjust your time as necessary. Often - depending on how your legacy solution is already coded, you should also useDateTime.ToUniversalTime
orDateTime.UtcNow
to use a UTC date which is based on zulu time (Greenwhich Mean Time). This ensures that your dates always have a common base. The clients use their locale information to get the local time. goodpilot wrote: By the way, what does Microsoft MVP mean? Are you a Most Valuable Player at Microsoft? It means "Most Valuable Professional". You can read more about the program at http://mvp.support.microsoft.com[^].Microsoft MVP, Visual C# My Articles