Roy Triesscheijn’s Weblog

My programming world

Custom XML Serialization in C#

Posted by Roy Triesscheijn on 24th October 2010

As people who follow me on twitter might know, I was working on a reflection tutorial for C#/XNA. However I got a bit carried away with the XML Serialization.

So here’s first an XML Serialization tutorial.

In previous tutorials/code-snippets I showed how to use the intermediate serializer. But for the tutorial I wanted to serialize all the XML by hand so that it would be crystal clear for anyone following the tutorial what was going on.

Quickly I coded up the following interface:

    public interface ISerializable
    {
        /// <summary>
        /// Allows the object to serialize itself into the current xml node
        /// </summary>
        void Serialize(XmlDocument document, XmlNode parent);

        /// <summary>
        /// Allows the object to reconstruct itself from the current xml node
        /// </summary>
        void Deserialize(XmlDocument document, XmlNode self);
    }

This code should be pretty self explanatory. Remember that an XmlDocument object is also an XmlNode. So for the root object you can pass your newly constructed XmlDocument as parent node.

I quickly created 3 classes:

-Block, a simple class with texture, position scale and tinting with the ability to draw itself.
-RotatbleBlock, child class of block, with the ability to rotate itself.
-Scene, a class containing a Block[] that draws all the blocks.

Both Scene and Block, and thus RotatableBlock, implement ISerializable.

Serializing is now easy (only relevant bits here):
In our static Serializer class we do this:

        public static void Save(ISerializable root, string fileName)
        {
            //Set the culture of the saving thread to InvariantCulture so that
            //we do not get problems with different decimal seperators and the likes
            //when trying to save and load in different countries
            CultureInfo userCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            XmlDocument document = new XmlDocument();
            root.Serialize(document, document);
            document.Save(fileName);

            //Restore the thread culture
            Thread.CurrentThread.CurrentCulture = userCulture;
        }

Take extra care to set the culture to invariant temporarily so that we don’t get different results depending on our computer’s localization settings.

Scene is serialized this way:

        public virtual void Serialize(XmlDocument document, XmlNode parent)
        {
            XmlElement me = document.CreateElement("ReflectionTutorialEngine.Scene");
            parent.AppendChild(me);

            XmlElement blocksElement = document.CreateElement("Blocks");
            me.AppendChild(blocksElement);

            foreach (Block b in blocks)
            {
                b.Serialize(document, blocksElement);
            }
        }

As you can see the object serialized just creates a new child node in the parent node. It’s name is it’s exact full namespace name (this will be important later).

The serialization code for Block is pretty straightforward too.

        public virtual void Serialize(XmlDocument document, XmlNode parent)
        {
            XmlElement me = document.CreateElement("ReflectionTutorialEngine.Block");
            parent.AppendChild(me);

            XmlElement textureNode = document.CreateElement("Texture");
            textureNode.InnerText = texture.Tag.ToString(); //the full asset name is saved in the tag elsewhere

            XmlElement positionNode = document.CreateElement("Position");
            positionNode.InnerText = position.X + ";" + position.Y;

            XmlElement scaleNode = document.CreateElement("Scale");
            scaleNode.InnerText = scale.ToString();

            XmlElement tintingNode = document.CreateElement("Tinting");
            tintingNode.InnerText = tinting.R.ToString() + ';' + tinting.G.ToString() + ';' + tinting.B.ToString() + ';' + tinting.A.ToString();            

            me.AppendChild(textureNode);
            me.AppendChild(positionNode);
            me.AppendChild(scaleNode);
            me.AppendChild(tintingNode);
        }

Where it get’s interesting is in the serialization code of RotatableBlock:

        public override void Serialize(XmlDocument document, XmlNode parent)
        {
            XmlElement me = document.CreateElement("ReflectionTutorialEngine.RotatableBlock");
            parent.AppendChild(me);

            XmlElement rotationElement = document.CreateElement("Rotation");
            rotationElement.InnerText = rotation.ToString();

            me.AppendChild(rotationElement);
            base.Serialize(document, me);
        }

As you can see we create an element for our object as normal. We also append anything we want to remember in child nodes in the XML. The interesting part is that we pass the newly created node as a root node for the Serialize method of the base class.

This approach generates the following XML:
(We saved a Scene which had an array of blocks, which contained one normal Block and one RotatableBlock using our Serializer’s Save method).

<ReflectionTutorialEngine.Scene>
  <Blocks>
    <ReflectionTutorialEngine.Block>
      <Texture>test</Texture>
      <Position>32;32</Position>
      <Scale>1</Scale>
      <Tinting>255;255;255;255</Tinting>
    </ReflectionTutorialEngine.Block>
    <ReflectionTutorialEngine.RotatableBlock>
      <Rotation>0.7853982</Rotation>
      <ReflectionTutorialEngine.Block>
        <Texture>test</Texture>
        <Position>64;64</Position>
        <Scale>0.5</Scale>
        <Tinting>245;245;220;255</Tinting>
      </ReflectionTutorialEngine.Block>
    </ReflectionTutorialEngine.RotatableBlock>
  </Blocks>
</ReflectionTutorialEngine.Scene>

Recreating the Scene, Block and RotatableBlock from this XML file is fairly easy. Let’s first declare a Load method in our Serializer.

        public static ISerializable Load(string fileName)
        {
            CultureInfo userCulture = Thread.CurrentThread.CurrentCulture;
            Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;

            XmlDocument document = new XmlDocument();
            document.Load(fileName);

            XmlNode rootNode = document.FirstChild;
            ISerializable rootObject = GetObjectFromNode(rootNode);
            rootObject.Deserialize(document, rootNode);

            Thread.CurrentThread.CurrentCulture = userCulture;

            return rootObject;
        }

        //Small helper method that creates an instance of ISerializable from a node
        public static ISerializable GetObjectFromNode(XmlNode node)
        {
            return (ISerializable)Assembly.GetExecutingAssembly().CreateInstance(node.Name);
        }

As you can see we load an XMLDocument normally. And start deserializing the first child of the document (the element in our case). I’ve added a little helper method (GetObjectFromNode) that actually does a lot of work. Via reflection it looks up the class stored in the name of the node. At first it will find “TutorialEngine.Scene” and it will thus create an instance of our Scene class.

After this we simply call Deserialize on our newly instantiated Scene object, giving it the XMlDocument and the node that represents the Scene itself.

Deserializing a Scene is now easy:

        public virtual void Deserialize(XmlDocument document, XmlNode self)
        {
            XmlElement blocksElement = self["Blocks"];

            blocks = new Block[blocksElement.ChildNodes.Count];
            for (int i = 0; i < blocks.Length; i++)
            {
                blocks[i] = (Block)Serializer.GetObjectFromNode(blocksElement.ChildNodes[i]);
                blocks[i].Deserialize(document, blocksElement.ChildNodes[i]);
            }
        }

See that we keep using the Serializer.GetObjectFromNode helper method to instantiate a block. Note that a RotatableBlock can be casted to a Block (we are using polymorphism here again). But that when deserialzing the overriden method in RotatableBlock will be used.

The deserialization code for a block is easy (and a bit dull)

        public virtual void Deserialize(XmlDocument document, XmlNode self)
        {
            try
            {
                texture = GameServices.GetService<ContentManager>().Load<Texture2D>(self["Texture"].InnerText);
                position.X = Single.Parse(self["Position"].InnerText.Split(';')[0]);
                position.Y = Single.Parse(self["Position"].InnerText.Split(';')[1]);
                scale = Single.Parse(self["Scale"].InnerText);
                tinting.R = Byte.Parse(self["Tinting"].InnerText.Split(';')[0]);
                tinting.G = Byte.Parse(self["Tinting"].InnerText.Split(';')[1]);
                tinting.B = Byte.Parse(self["Tinting"].InnerText.Split(';')[2]);
                tinting.A = Byte.Parse(self["Tinting"].InnerText.Split(';')[3]);
            }
            catch(Exception e)
            {
                throw new XmlException("Error deserializing from XML, see inner exception for details", e);
            }
        }

Note that we are using the GameServices class from a previous tutorial to get easy access to the ContentManager.

Now the interesting part is again in how we handled Inheritance in RotatableBlock, so let’s take a look at that code:

        public override void Deserialize(XmlDocument document, XmlNode self)
        {
            try
            {
                rotation = Single.Parse(self["Rotation"].InnerText);
                base.Deserialize(document, self["ReflectionTutorialEngine.Block"]);
            }
            catch (Exception e)
            {
                throw new XmlException("Error deserializing from XML, see inner exception for details", e);
            }
        }

As you can see we first set the rotation variable with the data saved in our XMLNode. However the special thing is that we now just deserialize the rest of our RotatableBlock data by calling the base.Deserialize method on the element inside our element. This way we don’t have to duplicate any code.

As you can see this is a pretty neat and clean way of writing your own XML Serialization code. It will save you a lot of work, and a lot of errors compared to writing the same boring serialization code for each object. If you have problems understanding inheritance and polymorphism I suggest that you quickly brush up on those techniques as they are crazy powerful and a must for every developer that works with an object oriented language as C#.

Be aware that there are multiple ways to automatically serialize your data, like the previously mentioned IntermediateSerializer, or using Xna.BinaryWriter.

I believe that the above code is as Xbox360 compatible as the other ways, and the nice thing is, is that it will also work when not using XNA at all :) .

Anyway, I hope you liked this. Stay tuned for the reflection tutorial for which I wrote this (yeah I did get carried away).

Tags: , , , , , ,
Posted in Blog, General Coding, General Gamedesign, XNA | 2 Comments »

XNA: Proxyclasses to ‘Serialize’ assets using the IntermediateSerializer

Posted by Roy Triesscheijn on 28th September 2010

As some of you’ve might seen, I’ve been breaking my head over the following problem for the past few days:

How do I serialize the class like the following without creating a special ‘intermediate’ struct for each and ever classes

public class MyData
    {
        [ContentSerializer(SharedResource = true)]
        public Texture2D myTexture;
        public int myInt;
        public string[] myLines;
        public MyData() { } // for deserialization
        public MyData(int myInt, Texture2DProxy myTexture, string[] myLines)
        {
            this.myInt = myInt;
            this.myTexture = myTexture;
            this.myLines = myLines;
        }
    }

Even though I’ve marked the Texture2D as a shared resource, I still can’t serialize it using the IntermediateSerializer because a Texture2D always has a reference to a GraphicsDevice object, and the IS can’t serialize that.

Fortunately some helpfull people in #XNA on Efnet (ecosky and flashed, that’s you guys!) told me about proxyclasses, first I was confused and thought they wanted me to write a proxy for every class in my project, but soon they helped me understand that I should write a proxy class for Texture2D. I just had to write a proxy class that can be serialized and that will store the path to texture, so that it can reload itself when deserialized.

I quickly came up with the following class, very simple but it will suffice for now:

public class Texture2DProxy
    {
        public Texture2DProxy(string path)
        {
            LoadTexture(path);
        }

        public Texture2DProxy() { }

        private void LoadTexture(string path)
        {
            ContentManager content = GameServices.GetService<ContentManager>(); //My own class, see my code snippet, you can also reference a static CM here.
            texture = content.Load<Texture2D>(path);
            this.path = path;
        }

        [ContentSerializerIgnore()] //make this is not serialized
        private Texture2D texture;

        [ContentSerializerIgnore()]
        public Texture2D Texture
        {
            get
            {
                if (texture == null)
                {
                    LoadTexture(path);
                }
                return texture;
            }
        }

        [ContentSerializer()] //make sure this is, even-though it's a private field.
        private string path;
    }

Now we just need to replace Texture2D with Texture2DProxy everywhere, and update some code. In the end we can now serialize and deserialize the MyData class like this:

public void DoSerialize(MyData myData)
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            using (XmlWriter writer = XmlWriter.Create("example.xml", settings))
            {
                IntermediateSerializer.Serialize(writer, myData, null);
            }
        }

        public MyData DoLoad()
        {
            MyData tmp;
            XmlReaderSettings settings = new XmlReaderSettings();
            using(XmlReader reader = XmlReader.Create("example.xml", settings))
            {
                tmp = IntermediateSerializer.Deserialize<MyData>(reader, null);
            }

            return tmp;
        }

Btw, serializing like this will generate the following XML file:

<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
  <Asset Type="XNASerialization.MyData">
    <myTexture>#Resource1</myTexture>
    <myInt>42</myInt>
    <myLines>
      <Item>Two households, both alike in dignity,</Item>
      <Item>In fair Verona, where we lay our scene,</Item>
      <Item>From ancient grudge break to new mutiny,</Item>
      <Item>Where civil blood makes civil hands unclean.</Item>
    </myLines>
  </Asset>
  <Resources>
    <Resource ID="#Resource1" Type="XNASerialization.Texture2DProxy">
      <path>latern</path>
    </Resource>
  </Resources>
</XnaContent>

With this problem out of the way, I can now finally start working on a way to save and restore levels in Hollandia. Oh btw, you can ofcourse do the same trick with SoundEffects and Models or anything else for that matter.

Tags: , , , , , ,
Posted in Blog, General Coding, General Gamedesign, Hollandia, Tips, XNA | 3 Comments »

Serialization: BLOB, INI, XML and JSON

Posted by Roy Triesscheijn on 12th April 2010

BLOB

As a regular programmer I was quite accustomed to storing program information as blob files (binary large objects). In C# this is really easy, you just mark a class as serializable via the [Serializable()] attribute, special fields that you don’t wish to be serialized you mark as [NonSerialized]. Finally you create a BinaryFormatter for the actual serialization and de-serialization and you’re done.
Source code (note: there’s no error handling in any of the source code to keep things short) would look something like this:

[Serializable()]
public class SerializeBLOB
{
	public string name = "Hello my name is...";

	[NonSerialized]
	public SerializeBLOB circularReference;

	public static void Serialize(SerializeBLOB obj, Stream stream)
	{
		BinaryFormatter bf = new BinaryFormatter();
		bf.Serialize(stream, obj);
	}

	public static SerializeBLOB DeSerialize(Stream stream)
	{
		BinaryFormatter bf = new BinaryFormatter();
		return (SerializeBLOB)bf.Deserialize(stream);
	}
}

Pointing the stream at a file would generate a binary file. Using blobs is very easy, it takes only a few lines of code to store and retrieve an object. However the generated output is not human readable. And a program which was written in a different language and/or has no access to the original class file (be it in compiled form or not) will not understand, let alone modify the file, correctly without a lot of effort.

INI

A different take on this are INI-files, which are files where an attribute is named and a value is followed. An ini file could look like this:

name=someName
number=18

This file is human readable and easily understood and edited by either computers or humans. This file was generated by the following code, which is not really complex, but there are some big problems which I haven’t solved yet.

public class SerializeINI
{
	public string name = "someName";
	public int number = 18;

	public static void Serialize(SerializeINI obj, Stream stream)
	{
		StringBuilder sb = new StringBuilder();
		sb.AppendLine("name=" + obj.name);
		sb.AppendLine("number=" + obj.number.ToString());
		StreamWriter writer = new StreamWriter(stream);
		writer.Write(sb.ToString());
	}

	public static SerializeINI DeSerialize(Stream stream)
	{
		StreamReader reader = new StreamReader(stream);
		SerializeINI obj = new SerializeINI();
		string line;
		while((line = reader.ReadLine()) != String.Empty)
		{
			string[] id_value = line.Split('=');
			switch (id_value[0])
			{
				case "name":
					obj.name = id_value[1];
					break;
				case "number":
					obj.number = Int32.Parse(id_value[1]);
					break;
			}
		}

		return obj;
	}
}

As you can see, serialization and de-serialization is not as automated as you’d hope for. We have to write the code for each action ourselves, which can be cumbersome if we are dealing with large and/or numerous classes. Also classes that we serialize need to have only public fields that we want to store, or have some kind of constructor (that maybe accepts a nice struct) that allows us to set all fields. There’s also another problem, there is no clear syntax on arrays, we could of course invent some syntax, but this would differ from program to program. Another problem is how do we save text that contains a ‘=’ char. We could solve this by using escaping or by using a special dummy character, although these problems are all solvable, the way these problems are solved differ from application, which makes it hard to make applications interact with each other.

In the comments Alex correctly states that with reflection you could get automatically get all the objects members automatically, you can even introduce your own attributes or respond to the existing attributes like [nonserialized]. Of course this would make ini serialization and de-serialization a lot easier. However reflection code is often very complex so I won’t put any source code here. But maybe I’ll write a separate tutorial about reflection.

XML

So let’s try another type of serialization, XML (eXtensible Markup Language) has been quite the buzz lately, it’s being used to create web pages (XHTML) and a lot of web services and web APIs communicate via XML. Some databases even allow us to save XML and to search through XML and in .Net there is even a separate XML namespace (System.XML). As with most things, it’s trivially easy to serialize to XML in .NET.

 <Human>
  <Name>Anthony</Name>
  <Age>38</Age>
 <Stuff  test='123'>something</Stuff>
</Human>

XML is human readable and very understandable by machines. However the syntax is a bit complex sometimes. The tree like structure is understandable, but when do we write an attribute between two tags like ‘Name’ or do we use the parameter syntax like in ‘Stuff’? Or both. There’s also a lot of confusion about arrays, we could use a tree like structure and creating a new leaf for each element in the array, but there are other solutions.
The syntax for serialization to XML looks quite like that of serialization to BLOB. We mark the class as serializable by setting it as a root element via [XMLRootAttribute(…)] and stuff we don’t want to serialize we mark with [XmlIgnore]. To beautify the XML output we can even add attributes to different fields to specify the arguments, type and name).

[XmlRootAttribute("TestRoot")]
public class SerializeXML
{
	public string name = "Hello my name is...";

	[XmlIgnore]
	public SerializeXML circularReference;

	public static void Serialize(SerializeXML obj, Stream stream)
	{
		XmlSerializer xs = new XmlSerializer(typeof(SerializeXML));
		xs.Serialize(stream, obj);
	}

	public static SerializeXML DeSerialize(Stream stream)
	{
		XmlSerializer xs = new XmlSerializer(typeof(SerializeXML));
		return (SerializeXML)xs.Deserialize(stream);
	}
}

JSON

JSON (JavaScript Object Notation) is not as well known as any of the previously mentioned techniques, also don’t mind the name, JSON is usable in any programming language. JSON is slightly easier to read and requires less typing than XML, the notation is much cleaner, and there is always only one way to store data. The graphs at http://json.org/ show how easy it is to learn how to read and write a JSON file (however the website is quite biased). A JSON file would look like this (from Wikipedia):

{
     "firstName": "John",
     "lastName": "Smith",
     "age": 25,
     "address": {
         "streetAddress": "21 2nd Street",
         "city": "New York",
         "state": "NY",
         "postalCode": "10021"
     },
     "phoneNumber": [
         { "type": "home", "number": "212 555-1234" },
         { "type": "fax", "number": "646 555-4567" }
     ]
 }

New knowledge for me is that JSON in .Net is fully integrated into the .Net Framework. But you have to manually add the references to “System.ServiceModel.Web” and System.Runtime.Serialization.XmlObjectSerializer to your project to take full advantage of this. Take a look at the following sourcecode:

    [Serializable()]
    public class SerializeJSON
    {
        //Add the references System.ServiceModel.Web
        //and System.Runtime.Serialization.XmlObjectSerializer
        //to your project to be able to see DataContractJSONSerializer
        public string name = "Hello my name is...";

        [NonSerialized]
        public SerializeJSON circularReference;

        public static void Serialize(SerializeJSON obj, Stream stream)
        {
            DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(SerializeJSON));
            js.WriteObject(stream, obj);
        }

        public static SerializeJSON DeSerialize(Stream stream)
        {
            DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(SerializeJSON));
            return (SerializeJSON)js.ReadObject(stream);
        }
    }
}

As you can see the JSON serialization syntax closely matches that of the BLOB (BinaryFormatter) syntax, which makes it easy to use, but there is less control over the output than with XML.

Conclusion

BLOB files are handy for data that doesn’t need to be edited by anything else than your own application, INI files are something from the past, but might still have a right to exist because it is so easy to edit them by hand, INI files are still heavily used in the game industry to set a lot of properties at game. Big engines like the Unreal Engine still use a lot of INI files. XML has a slightly more difficult syntax but you can give a lot of meaning to attributes and it is very customizable how attributes are stored. Also the support from the .NET framework is incredible and XML is a widely appreciated standard. JSON is less widely adopted than XML except in JAVASCRIPT driven web applications but JSON has a very clear syntax. However XML is more expressive as it is a bit more difficult to give extra meaning to an attribute in JSON than it is in XML, but JSON is a purer form of storing data where XML might be a bit too multi-purpose sometimes.
As with all techniques there is no ‘winner’, all techniques have their uses and I look forward to use all of them.

Other cool things to know is that JSON can be directly evaluated in javascript by using the eval(…) function. And for XML there is a full query language called XPATH which allows you to query your XML files like you would query a database.

Special thanks to creator1988 for pointing me to the JSON serializer.
kick it on DotNetKicks.com

Tags: , , , , , , ,
Posted in Blog, General Coding | 6 Comments »

Sending objects via high speed asynchronous sockets in C# (Serialization + Socket programming)

Posted by Roy Triesscheijn on 31st May 2009

Well a while has past since my last useful post here, but here I am at it again a post filled with usefull source code to use in your everyday C# programs.

I was very curious how games work with async sockets to keep everyone communicating smoothly so I set up a simple test app to test async sockets in C#, however this seemed quite a bit harder than I thought and after some help at the Dutch website tweakers.net I finally had everything working. (I finally figured out that I shouldn’t be using the beginsendpacket but the beginsend methods). Anyway let’s get straight to business.

I first made a small object that we want to send over the network, let’s call it Status, below is the source code for that object, let’s make a couple of stuff clear.

[Serializable]
    public class Status
    {
        [NonSerialized]
        public Socket Socket;
        [NonSerialized]
        public List<byte> TransmissionBuffer = new List<byte>();
        [NonSerialized]
        public byte[] buffer = new byte[1024];

        public string msg;     //the only thing we really send.

//Usually you shouldn't but these 2 methods in your class because they don't operate specifically on this object
//and we would get allot of duplicate code if we would put those 2 methods in each class we would like to
//be able to send but to not wind up having to write a couple of utility classes (where these should reside)
// I let them reside here for now.
        public byte[] Serialize()
        {
            BinaryFormatter bin = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            bin.Serialize(mem, this);
            return mem.GetBuffer();
        }

        public Status DeSerialize()
        {
            byte[] dataBuffer = TransmissionBuffer.ToArray();
            BinaryFormatter bin = new BinaryFormatter();
            MemoryStream mem = new MemoryStream();
            mem.Write(dataBuffer,0, dataBuffer.Length);
            mem.Seek(0, 0);
            return (Status)bin.Deserialize(mem);
        }
    }

As you can see the class is marked serializable with [Serializable] this signals the compiler that we should be able to serialize this object. (Get it from memory, place it in a byte array and send it anywhere (harddrive/network/etc..). Stuff that shouldn’t be send with it like external classes that we would like to send later should be marked [NonSerialized] (the Java equivalent for transient). This way we can cut of some dependencies and keep the overhead low. (For example no matter what the TransmissionBuffer referenced to, because it’s nonserialized it’s reference will not be send aswell and it will appear on the other side as “null”.

As you can see the only real data this object hold is a small string called msg the other objects are for administrative purposes as we will see soon.

Now there are allot of examples out there that show how to send a string, you can easily get the bytearray from a string and send it anywhere, for an object that is slightly harder, as you can see in the serialize() method we have to create a binarrayformatter, this binarray formatter is then fed a direct stream to the memory where our object resides and a reference to our memorystream, the object is serialized in our memorystream’s buffer as a bytearray and then we can do anything we want with it. This method just returns the buffer so we can set it over a network. The deserialize method does exactly the same but then the other way arround except for the mem.Seek(0,0); we see right before return, this seek sets the pointer of the stream at the start of the stream so the binarrayFormatter can start reading and deserializing from the start of the stream. (Forgetting this would give an error telling that the end of the stream was found before deserialzing was completed, which makes sence if you think about it).

Anyway before we get to the real workhorse of the code let’s take a look at the client.

public class Client
{
ManualResetEvent allDone = new ManualResetEvent(false);

///
/// Starts the client and attempts to send an object to the server
///
public void Start()
{
while (true)
{
Console.Out.WriteLine("Waiting for connection...");
allDone.Reset();
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.BeginConnect(new IPEndPoint(IPAddress.Loopback, 1440), Connect, sender);
allDone.WaitOne(); //halts this thread until the connection is accepted
}
}

///
/// Starts when the connection was accepted by the remote hosts and prepares to send data
///
public void Connect(IAsyncResult result)
{
Status status = new Status();
status.Socket = (Socket)result.AsyncState;
status.Socket.EndConnect(result);
status.msg = "Hello webs";
byte[] buffer = status.Serialize(); //fills the buffer with data
status.Socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, Send, status);
}

///
/// Ends sending the data, waits for a readline until the thread quits
///
public void Send(IAsyncResult result)
{
Status status = (Status)result.AsyncState;
int size = status.Socket.EndSend(result);
Console.Out.WriteLine("Send data: " + size + " bytes.");
Console.ReadLine();
allDone.Set(); //signals thread to continue so it sends another message
}
}

Don’t mind the manualreset events to much, they’re there so the application doesn’t go to fast so we can see what happens instead of 2 console windows just printing text like mad :) . (Remember that they will send as fast as possible because they are asynchronous and don’t have to wait for the first send to complete so yeah some pause points are quite handy for now, in a real client you wouldn’t use while(true) but something more sophisticated like an update interval or when something changed.

As you can see the start method creates a socket and tries to send some data nothing super special here except for that the beginconnect method references the connect method. When the server is ready for a connection the connect method is executed, we create a new status object and place the socket we get returned from the endAccept method in there for bookkeeping (we need it later to send data else we don’t know which socket we where using, this is also why the socket is [unserialized] we don’t need to send it the other way). We also fill the msg of the object and then serialize it to a byte array, we place that bytearray in the beginsend method.

When the server is ready for receiving data the Send method is called. This method uses the socket in the packet to call endsend and read how many bytes where send.

And now, the server!

public class Server
{
ManualResetEvent allDone = new ManualResetEvent(false);

///
/// Starts a server that listens to connections
///
public void Start()
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Loopback, 1440));
while (true)
{
Console.Out.WriteLine("Waiting for connection...");
allDone.Reset();
listener.Listen(100);
listener.BeginAccept(Accept, listener);
allDone.WaitOne(); //halts this thread
}
}

///
/// Starts when an incomming connection was requested
///
public void Accept(IAsyncResult result)
{
Console.Out.WriteLine("Connection received");
Status status = new Status();
status.Socket = ((Socket)result.AsyncState).EndAccept(result);
status.Socket.BeginReceive(status.buffer, 0, status.buffer.Length, SocketFlags.None, Receive, status);
}

///
/// Receives the data, puts it in a buffer and checks if we need to receive again.
///
public void Receive(IAsyncResult result)
{
Status status = (Status)result.AsyncState;
int read = status.Socket.EndReceive(result);
if (read &gt; 0)
{
for (int i = 0; i &lt; read; i++)
{
status.TransmissionBuffer.Add(status.buffer[i]);
}

//we need to read again if this is true
if (read == status.buffer.Length)
{
status.Socket.BeginReceive(status.buffer, 0, status.buffer.Length, SocketFlags.None, Receive, status);
Console.Out.WriteLine("Past niet!");
}
else
{
Done(status);
}
}
else
{
Done(status);
}
}

///
/// Deserializes and outputs the received object
///
public void Done(Status status)
{
Console.Out.WriteLine("Received: " + status.msg);
Status send = status.DeSerialize();
Console.WriteLine(send.msg);
allDone.Set(); //signals thread to continue
//So it jumps back to the first while loop and starts waiting for a connection again.
}
}
}

Well start and accept basically do the same as the client but then the other way around, the only big difference we have is the receive method which endreceives() the data, but it’s not done yet, first it has to check if all the bytes where received if not we have to put the object in a listening state again to get the rest of the bytes from the networkcard. Then when all the bytes are safely inside our Transmissionbuffer we deserialize our object and print the msg we place in it.

Allot of work to just send a string accros, but this code will work any object and make your server nonblocking which could make it much faster, just instead of putting “string msg” in your status object put “TheObjectYouWant obj” in your status object and you are free todo as you please.

Feel free to ask questions and comments, the full sourcecode is available here: AsyncSocketServer+Client.rar

Tags: , , , , , ,
Posted in Blog, General Coding | 23 Comments »