C # send structure objects via socket

I read a little in client / server programming in C #. I am familiar with this process enough to ask the following question:

how to pass structure objects via tcp / ip instead of simple strings?

my application is an online game with chat features. so instead of just passing text, I would like to implement a data structure or class structure that will have two fields: i. type of package ii. data for package type

and I will pass this if necessary at runtime and decodes the data object at the receiving end and put it where it belongs.

im not looking for code, just some ideas and search operators that I can submit to Google, so I will; have a better understanding.

ive read about serialization / serialization, is that it going to go?

thanks.


I checked the posts that appeared as related topics, but still would like more information.


+6
c # sockets tcp
source share
6 answers

You can create a Socket-based NetworkStream and use any Stream engine to transport your data. This translates your question to: How can I read / write a structure from / to a stream.

You can use Serialization, but also BinaryWriter / BinaryReader. For a small structure (as you described) I would write some custom methods:

var netStream = new NetworkStream(clientSocket, true); var writer = new BinaryWriter(netStream); writer.Write(data.Value1); writer.Write(data.Value2); 

For larger structures, I would consider the Cheeso Marshaling option.

+3
source share

Ultimately, yes: you're talking about serialization. This can take many forms, especially in .NET, but ultimately you need to choose between:

  • text vs binary; a direct binary tends to be smaller than text, as it usually involves less parsing, etc .; text (xml, json, etc.) is usually represented in the stream as UTF8 (although any encoding is possible). They are widely readable to humans, and although they are more detailed, you can usually compress them pretty well.
  • contract against metadata; contract-based serializers focus on the presentation of data - it is assumed that the other end of the channel understands the structure, but it is not assumed that they use an implementation. This has limitations in that you cannot suddenly introduce some completely unexpected subclass, but makes it platform independent. In contrast, metadata-based serializers send type information to a stream (i.e., "This is an instance of My.Namespace.FooBar ). This makes the work very simple, but rarely works between different platforms (and often not between versions) - and all the information this type can be verbose.
  • manual and automatic; fact: manual serializers can often be the most efficient in terms of bandwidth, since you can manually configure the worm from the stream, but it takes a lot of effort and you need to understand serialization. Automatic serializers are much better used for general use (in reality: most scenarios). Avoid leadership if you have no choice. Automatic serializers handle all the complexities associated with various types of data, etc.

Manual serializer approaches include (just mentioning the keyword "serializer"): TextWriter , XmlWriter , IXmlSerializable , BinaryWriter , ISerializable . You do not want to do this ...

Focus on automatic serializers:

  | Contract | Metadata ===============+========================+=========================== Text | XmlSerializer | SoapFormatter | DataContractSerializer | NetDataContractSerializer | Json.NET | ---------------+------------------------+--------------------------- Binary | protobuf-net | BinaryFormatter 

Since you're talking about raw streams, my preference would be a binary contract serializer, but then I wrote protobuf-net , so I can be biased; -p

For comparison with common RPC packages:

  • "remote access" uses BinaryFormatter
  • "asmx" web services (including WSE *) use XmlSerializer
  • WCF can use a lot, most often DataContractSerializer or NetDataContractSerializer , and sometimes XmlSerializer (it can also be configured to use, for example, protobuf-net)

I can happily write an example of using protobuf-net in a stream to represent different messages of different types, but a simple example of processing sockets using protobuf-net is in one of the example projects ( here, in fact )

+7
source share

Serialization is the easiest way, because the system supports it directly. However, there are some problems with large and complex objects. In your case, this is similar to serialization - this is the way to go. If you have something lower level, you can check out BinaryWriter / BinaryReader, which allows you to do your work yourself.

+5
source share

If you don't want serialization richness — if you just want to write a structure to an array of bytes, consider a marshal class.

For example, consider a tar application in C #. The tar format is based on 512-byte blocks, and the first block in the series has a regular structure. Ideally, an application just wants to blitt data from a disk file, right into the structure. This method is Marshal.PtrToStructure . Here is the structure.

  [StructLayout(LayoutKind.Sequential, Size=512)] internal struct HeaderBlock { [MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)] public byte[] name; // name of file. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] mode; // file mode [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] uid; // owner user ID [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] gid; // owner group ID [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] size; // length of file in bytes [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12)] public byte[] mtime; // modify time of file [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] chksum; // checksum for header // ... more like that... up to 512 bytes. 

Then here is a generic class that does blitting.

 internal class RawSerializer<T> { public T RawDeserialize( byte[] rawData ) { return RawDeserialize( rawData , 0 ); } public T RawDeserialize( byte[] rawData , int position ) { int rawsize = Marshal.SizeOf( typeof(T) ); if( rawsize > rawData.Length ) return default(T); IntPtr buffer = Marshal.AllocHGlobal( rawsize ); Marshal.Copy( rawData, position, buffer, rawsize ); T obj = (T) Marshal.PtrToStructure( buffer, typeof(T) ); Marshal.FreeHGlobal( buffer ); return obj; } public byte[] RawSerialize( T item ) { int rawSize = Marshal.SizeOf( typeof(T) ); IntPtr buffer = Marshal.AllocHGlobal( rawSize ); Marshal.StructureToPtr( item, buffer, false ); byte[] rawData = new byte[ rawSize ]; Marshal.Copy( buffer, rawData, 0, rawSize ); Marshal.FreeHGlobal( buffer ); return rawData; } } 

You can use this class with any structure. You must use LayoutKind.Sequential and restrict yourself to blittable types (mostly primitives and arrays of the same thing) in order to use this approach. It is fast and efficient in terms of code, performance and memory, but it is slightly limited in how it can be used.

Once you have an array of bytes, you can pass it through NetworkStream or the like, and then de-serialize using the same class on the other end.

+5
source share

.NET binary serialization is likely to be the fastest out-of-the-box option, assuming that both sides of the communication mechanism are C # and can load the same assembly containing message types. Rolling your own serialization is probably very good, though, if your structures are very simple. Just define your data structure in the class, as well as the method for converting it to and from the string.

+1
source share

You are on the right track using object serialization.

One thing that I would think about that I haven't mentioned about this yet is that binary serializers usually create fewer bytes to send over a socket, however if you use an XML or JSON serializer and then compress the results using CompressionStream (GZipStream?) before sending over a network stream, you can even get smalelr sizes depending on the type of data in your object (this works best when you have many lines).

This will require more CPU time to send and read messages, so its a compromise if you need to reduce bandwidth requirements.

+1
source share

All Articles