How to Serialize an Object Using Tcpserver Inside

Serializing object ready to send over TCPClient Stream

Assuming you have a class House (available on both sides of your connection) looking like this:

[Serializable]
public class House
{
public string Street { get; set; }
public string ZipCode { get; set; }
public int Number { get; set; }
public int Id { get; set; }
public string Town { get; set; }
}

You can serialize the class into a MemoryStream. You can then use in your TcpClient connection like this:

// Create a new house to send house and set values.
var newHouse = new House
{
Street = "Mill Lane",
ZipCode = "LO1 BT5",
Number = 11,
Id = 1,
Town = "London"
};

var xmlSerializer = new XmlSerializer(typeof(House));
var networkStream = tcpClient.GetStream();
if (networkStream.CanWrite)
{
xmlSerializer.Serialize(networkStream, newHouse);
}

Of course you have to do a little more investigation to make the program running without exception. (e.g. Check memoryStream.Length not to be greater than an int, a.s.o.), but I hope I gave you the right suggestions to help you on your way ;-)

Serialize and send objects by TCP using boost

Here you can find a good example on how to use boost::serialization together with boost::asio.

Something like this is the core of what you need:

std::ostringstream archive_stream;
boost::archive::text_oarchive archive(archive_stream);
archive << YOUR_DATA;
outbound_data_ = archive_stream.str();
boost::asio::async_write(socket_, boost::asio::buffer(outbound_data_), handler);

Sending and receiving custom objects using Tcpclient class in C#

When receiving on client side you do not know how much data you want to read.
You are only relying on the ReceiveBufferSize, while your data can be larger
or smaller then that.

I think the best approach here is to send 4 bytes that tells your client about the length of incoming data:

byte[] userDataLen = BitConverter.GetBytes((Int32)userDataBytes.Length);
netStream.Write(userDataLen, 0, 4);
netStream.Write(userDataBytes, 0, userDataBytes.Length);

and on the recieving end you first read the data length and then read
exact amount of data.

byte[] readMsgLen = new byte[4];
readNetStream.Read(readMsgLen, 0, 4);

int dataLen = BitConverter.ToInt32(readMsgLen);
byte[] readMsgData = new byte[dataLen];
readNetStream.Read(readMsgData, 0, dataLen);

Infact, I just realized, that you might has to do a little more to assure you read all data (just an idea because I haven't tried it, but just incase you run into problem again you can try this).

The NetworkStream.Read() method returns a number indicating the amount of data it has read. It might be possible that the incoming data is larger then the RecieveBuffer. In that case you have to loop until you read all of the data. You have to do something like this:

SafeRead(byte[] userData, int len)
{
int dataRead = 0;
do
{
dataRead += readNetStream.Read(readMsgData, dataRead, len - dataRead);

} while(dataRead < len);
}

Sending an object over a TCP server network in python

You could use pickle to serialize/deserialize objects to strings and back. https://docs.python.org/2/library/pickle.html

Send typed objects through tcp or sockets

I have one approach I would recommend and two lesser ones which are dependent on many things.

The first one implies you already know how to use the Socket class but have a lot of classes that you need to send through it.

From a transport point of view you should create / take into consideration just one very simple class. Let's call this class MyMessage:

public class MyMessage {
public byte[] Data { get; set; }
}

Ok. From a TCP point of view all you need to do is make sure you're able to pass instances of this class around (from clients to the server and back). I will not dive into the details of doing that but I will point out that if you manage to do this you transform the nature of the TCP/IP connection from "byte-stream" to "message-stream". What that means is that normally, TCP/IP does not guarantee that chunks of data you send through a connection arrive at the destination in the same formations (they might get joined together or be split apart). The only thing it guarantees is that the bytes of all the chunks will eventually arrive in the same order at the other end of the connection (always).

Now that you have a message-stream up and running you could use .NET good old serialization to encapsulate any class instance inside the Data property. What that does is it serializes object graphs into bytes and vice-versa.

The way you do that (most commonly) is to use the standard library class:
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
which can be found in mscorlib.dll like so:

public static class Foo {

public static Message Serialize(object anySerializableObject) {
using (var memoryStream = new MemoryStream()) {
(new BinaryFormatter()).Serialize(memoryStream, anySerializableObject);
return new Message { Data = memoryStream.ToArray() };
}
}

public static object Deserialize(Message message) {
using (var memoryStream = new MemoryStream(message.Data))
return (new BinaryFormatter()).Deserialize(memoryStream);
}

}

The BinaryFormatter class is able to traverse the tree/graph of objects starting from the root / sentinel provided as the second argument of the Serialize (Stream, object) method and write all of the primitive values plus type information and relative position information to the provided stream.
It is also able to do the exact reverse and deserialize an entire object graph as long as the provided stream is positioned accordingly to the place of a former object graph serialization.

There are a few catches here though: you will need to annotate all of your classes with [SerializableAttribute]. If your classes contain fields that are of other classes written by you, and you said they do:

[SerializableAttribute]
public class Player {
public PlayerInfo Info;
//... etc

then you need to annotate those with [SerializableAttribute] too:

[SerializableAttribute]
public class PlayerInfo { //... etc

If your classes contain fields that are of types written by others (say Microsoft) then those would better be already annotated with the attribute. Most of those which could be serialized already are. Primitive types are naturally serializable. Things that shouldn't be serialized are: FileStreams, Threads, Sockets, etc.

After making sure you have serializable classes all you need to do is serialize their instances, send them, receive them and deserialize them:

class Client {

public static void SendMovement(Movement movement) {
Message message = Foo.Serialize(movement);

socketHelper.SendMessage(message);
}
public static void SendPlayer(Player player) {
Message message = Foo.Serialize(player);

socketHelper.SendMessage(message);
}
// .. etc

public static void OnMessageReceivedFromServer(Message message) {
object obj = Foo.Deserialize(message);
if (obj is Movement)
Client.ProcessOtherPlayersMovement(obj as Movement);
else if (obj is Player)
Client.ProcessOtherPlayersStatusUpdates(obj as Player);
// .. etc
}

public static void ProcessOtherPlayersMovement(Movement movement) {
//...
}
// .. etc

}

While on the server side:

class Server {

public static void OnMessageReceived(Message message, SocketHelper from, SocketHelper[] all) {
object obj = Foo.Deserialize( message );
if (obj is Movement)
Server.ProcessMovement( obj as Movement );
else if (obj is Player)
Server.ProcessPlayer( obj as Player );
// .. etc

foreach (var socketHelper in all)
if (socketHelper != from)
socketHelper.SendMessage( message );
}
}

You will need a common assembly project (class library) to be referenced by both executable projects (client and server).

All your classes that need to be passed around will have to be written in that assembly so as that both the server and the client know how to understand each other at this very detailed level.

If the server needs not understand what is being said between the clients and only pass around messages (broadcasting one message to the other N-1 clients) then forget what I said about the common assembly. In that particular case, the server sees only bytes, while the clients have a deeper understanding of the actual messages being sent back and forth.

I said I had three approaches.

The second one involves .NET Remoting which can take a lot of work off your shoulders but which is hard to live with if you don't fully understand it. You can read about it on MSDN, here: http://msdn.microsoft.com/en-us/library/kwdt6w2k(v=vs.100).aspx

The third one would be better only if (now, or in the future) by XNA you mean Windows Phone or another implementation of XNA which does not support the BinaryFormatter class (ExEn with MonoTouch, or others).
In that case you would have a hard time if you needed your server (a full blown, good old fashioned .NET application) to reference the common assembly I talked about and also have the game project (which would not be a good old fashioned .NET app but have a rather exotic nature) reference the exact same assembly.

In that case we would need to use and alternate form of serializing and deserializing your objects. You would also need to identically implement two sets of classes in the two worlds (.NET and WP7 or WP8). You could use some form of XML serializers which you would need to map to your classes explicitly (not as powerful as the BinaryFormatter class but more versatile in what the nature of the runtime that host your classes could be).

You can read about the XmlSerializer class on MSDN, here: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

C# Deserializing a struct after receiving it through TCP

Instead of having a string represent your packet length and then subtract by the string's length to know where to start reading, you should implement proper length-prefixing. Length-prefixing combined with a data header will make you able to read every packet according to its size, then the data header will help you determine what to do with the data.

Ordinary length-prefixing adds a fixed header to every "packet" you send. To create this header you convert an integer (the length of your data) to bytes, which will result in 4 bytes, then you add the data header after that and also the rest of the packet (which is the data you want to send).

This will create the following packet structure:

[Length (4 bytes)][Header (1 byte)][Data (x byte(s))]

Reading a packet is very simple:

  1. Read the first 4 bytes (Length), convert and assign them to an integer variable.

  2. Read the next byte (the data header) and put that in a variable.

  3. Read x bytes to a byte array (where x is the integer you declared in step 1).

  4. Use the data header from step 2 to determine what to do with your data (the byte array from step 3).

In one of my previous answers you can see an example of what I just explained above.



Related Topics



Leave a reply



Submit