5,446,542 members and growing! (17,124 online)
Email Password   helpLost your password?
Web Development » Ajax and Atlas » General     Advanced License: The Code Project Open License (CPOL)

FreeDOM (programming)

By VectorX

(Free Document Object Model) is a web development technique used for creating event driven web applications. FreeDOM is designed to overcome the limitations of stateless HyperText Transfer Protocol (HTTP) transmissions.
VBScript, Javascript, XML, CSS, HTML, JScript .NET, C# 1.0, C# 2.0, C# 3.0, C#, .NET, Windows, Win2K, WinXP, Win2003, Vista, IE, Ajax, VS.NET2002, VS.NET2003, VS2005, VS2008, Visual Studio, Design, Architect, Dev

Posted: 30 Oct 2007
Updated: 15 Dec 2007
Views: 28,491
Bookmarked: 56 times
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
13 votes for this Article.
Popularity: 4.77 Rating: 4.29 out of 5
0 votes, 0.0%
1
1 vote, 7.7%
2
1 vote, 7.7%
3
2 votes, 15.4%
4
9 votes, 69.2%
5
Note: This is an unedited contribution. If this article is inappropriate, needs attention or copies someone else's work without reference then please Report This Article

Please be patient, more source files and demos coming soon!

Introduction

What is FreeDOM? Well FreeDOM is a new concept I created that changes a webpage into a fully asynchronous event driven application by using current available technologies. Below I will compare FreeDOM with currently working Web 2.0 concepts and show you the benefits of switching to this architecture.

Web 2.0 Techniques

There are many ways of creating webpages that go and get content from servers and update themselves. Below is a list of common ways.

  1. Ajax - An ActiveX object built into browsers that send and receive text or xml HTTP requests.
  2. IFrame - A built in browser element control that can send and request webpage content similar to Ajax.
  3. Comet - A concept of leaving a webpage in a state of constant downloading that simulates an HTTP push technology, to receive data events.
  4. HTTP Streaming - Using third party technologies such as Java Applets or Activex to stream data from server to client.

Most of these concepts come with plenty of downfalls to true application state. Ajax and Iframes, both are very resource happy. Everytime you want to get data from the server you must create an object or element and send an HTTP Request. This causes the http server to have huge amounts of requests eating up memory and processor time. There is also a delay in response time do to header information being passed back and forth. Also Ajax and Iframes do not know if there is data available, they have to send a request just to find out if it is available, an once again causing alot of not needed talking between server and client. Another issue with HTTP Requests is that it fills up your server logs. This can be a headache for servers with large amounts of traffic. Extremely large logs take up processor time, harddrive space and backup space. Ajax/Frames also can only receive text or XML. This can be very irratating because in order to use it on a page you must convert it into a usable format. Alot of websites use XML objects backend and JSON objects front end, in doing this they must have a conversion process. This is at another memory and processor expense.

Screenshot - ajaxprocessing.gif

Alot of developers have notice these flaws in Ajax and IFrames and have started to invent new technologies. One being Comet, another cleansing name. Comet is very hard to implement and comes with alot of unknown bugs. Basically in order to use it you usually have to create a custom web server, because most today were not made to leave requests in an open state. Most servers have timeouts and caching built in to make them faster for a get in get out way of doing business. Comet is a step up from Ajax but its not the cure. Comet can only receive asynchronous events, it cannot talk back to the server. You need to implement Comet to receive and Ajax to send, making Coment dependant on Ajax. Another downside of using Comet is that browsers also have an issue with a never ending webpage. Have you ever been on a page and it locks up causing all your other browsers windows to close... this is caused by the exe sharing memory and thread space. So Comet was a great idea but it is not feasable do to current technology.

Screenshot - cometprocessing.gif

Another technology is HTTP Streaming. There is many different versions of http streaming. One way is setting up a server to talk back and forth to ActiveX or Java Applet. Very hard to implement and maintain, with many security and licensing issues for both client and server. Most users will not install your code because of fears of corrupt code that they will not be able to remove, plus cause damage to their operating system or files. This can be very scary to the end user.

This next section I will describe FreeDOM and how it will fix these issues.

FreeDOM!

So how would one go about fixing these old technologies to make websites and application one. Should we wait for large companies to create better working browsers or should we invent it now with currently working technologies. As a developer I feel I should wait... but as an inventor I have decided to make it work. What I want is the freedom to do what I want and build what i want on a webpage. I came up with the name FreeDOM for this reason, plus it is really what we want to do. We want to be able to work with the browser DOM freely and update it whenever we choose. So I asked myself what current technologies could i use to create a true event state application. One that came to mind was Flash, with so much new hype around AIR and Flex applications. Its hard not to notice a big boom in flash usage everywhere since Adobe took over it from Macromedia. Some of the latest usage has said flash is installed on 90% or more of the machines world wide across operating systems and browsers. This got me thinking! Could I use flash in some way with my currently working webpage technology? Flash seems to work well for creating banners and animation, but could it handle passing data back and forth. After some testing with ActionScript 3.0 I have figured out a way to replace Ajax, Iframes, Comet and HTTPStreaming. I am sure though you could probably use SilverLight the same way, which I am currently looking into, maybe some MS guys could help figure that out for me.

How Does FreeDOM Work?

FreeDOM works by using Flash Binary Sockets to communicate with your Custom Socket Server. To pass binary data from Flash sockets to your javascript webpage you need a custom class called ExternalInterface. This class will allow you to make calls to flash methods and add callbacks for your javascript methods. So lets see some code so you will understand.

Screenshot - FreeDOMProcessing.gif

Flash SWF Code

Add the following code to a document class .AS file. It is a wrapper for the custom JSocket class and main movie clip. Please keep in mind to keep the size of this and your jsockets small. By keeping them small you can load everything in the first preloader frame and bypass the activate SWF message.

package {
 //Imports--------------------

 import flash.external.ExternalInterface;//For communicating with javascript

 import JSockets.JSocket;//JSocket

 import flash.display.MovieClip;//Movie Clip

 import flash.system.Security;//For Domain Security

 
 import flash.text.TextField;
 import flash.text.TextFieldAutoSize;
 import flash.text.TextFormat;
 //---------------------------

 //Main Class for creating javascript sockets

 public class Main extends MovieClip {
  //Create Properties----------------

  private var SocketArray:Array;
  //---------------------------------

  
  //Constructor

  public function Main() {
     
   //Add Javascript EntryPoints-------------------

   ExternalInterface.addCallback("CreateSocket", this.CreateSocket);
   ExternalInterface.addCallback("Connect", this.Connect);
   ExternalInterface.addCallback("Close", this.Close);
   ExternalInterface.addCallback("Flush", this.Flush);
   ExternalInterface.addCallback("Send", this.Send);
   //---------------------------------------------

  }
  //Creates a socket for use in javascript

  public function CreateSocket(_ID:String, _Cls:String, _Con:String,
 _Ioe:String, _Se:String, _Dat:String):void {
   var NS:JSocket = new JSocket();
   NS.ID = _ID;
   NS.CloseEventCallback = _Cls;
   NS.ConnectEventCallback = _Con;
   NS.IOErrorEventCallback = _Ioe;
   NS.SecurityErrorEventCallback = _Se;
   NS.SocketDataEventCallback = _Dat;
   this.SocketArray = new Array();
   this.SocketArray.push(NS);
  }
  //Gets the socket object

  private function GetSocket(_ID:String):JSocket {
   for each (var S:JSocket in this.SocketArray) {
    if (S.ID == _ID) {
     return S;
    }
   }
   return null;
  }
  //Connects to a host and port

  public function Connect(_ID:String, _Host:String, _Port:uint):void {
   //Get Working Socket----

   var FS:JSocket = this.GetSocket(_ID);
   //----------------------

   
   if (FS) {
    FS.Connect(_Host, _Port);
   }
  }
  //Closes a connection to a host

  public function Close(_ID:String):void {
   //Get Working Socket----

   var FS:JSocket = this.GetSocket(_ID);
   //----------------------

   if (FS) {
    FS.close();
   }
  }
  //Flushes a connection

  public function Flush(_ID:String):void {
   //Get Working Socket----

   var FS:JSocket = this.GetSocket(_ID);
   //----------------------

   if (FS) {
    FS.flush();
   }
  }
  //Sends data to a connection

  public function Send(_ID:String, _Data:String):void {
   //Get Working Socket----

   var FS:JSocket = this.GetSocket(_ID);
   //----------------------

   
   if (FS) {
    FS.writeUTFBytes(_Data);
   }
  }
 }
}

Next is the JSocket Class which wrappers the flash sockets class. Below is the code for that.

package JSockets{
 //Imports--------------------

 import flash.external.ExternalInterface;//For communicating with javascript

 import flash.net.Socket;//Flash Socket Class

 import flash.errors.*;//Flash Errors

 import flash.events.*;//Flash Events

 //---------------------------

 //Actual socket class

 public class JSocket extends Socket {
  //Create Properties---------------

  public var ID:String;
  public var Host:String;
  public var Port:uint;
  public var CloseEventCallback:String;
  public var ConnectEventCallback:String;
  public var IOErrorEventCallback:String;
  public var SecurityErrorEventCallback:String;
  public var SocketDataEventCallback:String;
  //--------------------------------

  //Constructor

  public function JSocket() {
   AttachEvents();
  }
  //Attach Events

  private function AttachEvents():void {
   //Add Event Handlers-------------------------------------------------------

   addEventListener(Event.CLOSE, Handler_Close);
   addEventListener(Event.CONNECT, Handler_Connect);
   addEventListener(IOErrorEvent.IO_ERROR, Handler_IOError);
   addEventListener(SecurityErrorEvent.SECURITY_ERROR, Handler_SecurityError);
   addEventListener(ProgressEvent.SOCKET_DATA, Handler_SocketData);
   //-------------------------------------------------------------------------

  }
  //Connects to a host and port

  public function Connect(_Host:String, _Port:uint):void {
   Host = _Host;
   Port = _Port;
   //Call socket connect---

   connect(Host,Port);
   //----------------------

  } 
  // Handles the close event

  private function Handler_Close(event:Event):void {
   ExternalInterface.call(this.CloseEventCallback, event.type);
  }
  // Handles the connect event

  private function Handler_Connect(event:Event):void {
   ExternalInterface.call(this.ConnectEventCallback, event.type);
  }
  // Handles if io error event

  private function Handler_IOError(event:IOErrorEvent):void {
   ExternalInterface.call(this.IOErrorEventCallback, event.type, event.text);
  }
  // Handles security error event

  private function Handler_SecurityError(event:SecurityErrorEvent):void {
   ExternalInterface.call(this.SecurityErrorEventCallback, event.type, event.text);
   
  }
  // Handles socket data event

  private function Handler_SocketData(event:ProgressEvent):void {
   ExternalInterface.call(this.SocketDataEventCallback, event.type, this.readUTFBytes(this.bytesAvailable));
  }
 }
}

There is alot of tweaks you can do to these classes to customize it to your needs. These are just simple examples that I got my test app to work with. Keeping the flash as a simple byte router is the best solution.

Javascript Implementation

Lets see how to use these classes in Javascript. The code below is for the FreeDOM chat program example. It simulates a custom personal irc. If the page is not up its because im updating it. Here is the code for that example. Please keep in mind, this is a simple test, it doesn't support validation or bugs, use at your own risk.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"%22%3C/span">%22%3C/span">http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd<html xmlns="
http://www.w3.org/1999/xhtml">http://www.w3.org/1999/xhtml<head>

    <title>Test</title>
</head>
<script type="text/javascript">
function Connect()
{
 var f = thisMovie("flashObject");
 f.CreateSocket("id1", "CloseEventCallback", 
"ConnectEventCallback", "IOErrorEventCallback", 
"SecurityErrorEventCallback", "SocketDataEventCallback");
 f.Connect("id1", "%22%22%3C/span%22">
%22%3C/span">%22%3C/span">http://www.codevendor.com/">www.codevendor.com}
function DisConnect()
{
    var f = thisMovie("flashObject");
    f.Send("id1", "Logout: \n");
    f.Flush("id1");
}
function thisMovie(movieName) 
{
    return (navigator.appName.indexOf("Microsoft") != -1)?
window[movieName]:document[movieName];
}
function SendMessage()
{
    var M = document.getElementById("Message").value;
    document.getElementById("Message").value = "";
    var f = thisMovie("flashObject");
    f.Send("id1", "MESSAGE: " + M + "\n");
    f.Flush("id1");
}
function SendCommand()
{
    var M = document.getElementById("CommandBox").value;
    document.getElementById("CommandBox").value = "";
    var f = thisMovie("flashObject");
    f.Send("id1", M + "\n");
    f.Flush("id1");
}
function CloseEventCallback(T)
{
    document.getElementById("Status").value+=" -> " + T + "\n";
    
    ScrollToBottom();
}
function ConnectEventCallback(T)
{
    document.getElementById("Status").value+=" -> " + T + "\n";
    ScrollToBottom();
    GetUsers();
}
function GetUsers()
{
    var f = thisMovie("flashObject");
    f.Send("id1", "USERS: ");
    f.Flush("id1");
}
function IOErrorEventCallback(T, E)
{
    document.getElementById("Status").value+=" -> " + T + "\n";
    document.getElementById("Errors").innerHTML+=" -> " + E + "\n";
    
    ScrollToBottom();
}
function SecurityErrorEventCallback(T, E)
{
    document.getElementById("Status").value+=" -> " + T + "\n";
    document.getElementById("Errors").innerHTML+=" -> " + E + "\n";
    
    ScrollToBottom();
}
function SocketDataEventCallback(T, D)
{
    eval("D2 = " + D);
    if(D2.CMD == "USERLIST" || D2.CMD == "LOGOUT")
    {  
        document.getElementById("Users").value = D2.DATA.split(",").join("\n"); 
        document.getElementById("ChatRoom").value+= D2.STAT + "\n";
    }
    if(D2.CMD == "MESSAGE")
    {
        document.getElementById("ChatRoom").value+= D2.STAT + "\n";
    }
    
    document.getElementById("Status").value+=" -> " + T + "\n";
    document.getElementById("Data").value+=D + "\n";
    
    ScrollToBottom();
}
function ScrollToBottom()
{
    document.getElementById("ChatRoom").scrollTop =
 document.getElementById("ChatRoom").scrollHeight;
    document.getElementById("Status").scrollTop = 
document.getElementById("Status").scrollHeight;
    document.getElementById("Data").scrollTop = 
document.getElementById("Data").scrollHeight;
    document.getElementById("Errors").scrollTop =
 document.getElementById("Errors").scrollHeight;
}
</script>
<body>
    <table cellpadding="0px" cellspacing="10px">
        <tr>
            <td valign="top"><strong>Client Chat</strong><br /><br />
                <input type="button" onclick="Connect();"
 name="Connect" value="Connect" />  <input type="button" onclick="DisConnect();" 
name="DisConnect" value="DisConnect" />
               <br /><br /><table><tr><td>Chat Room</td><td>
Users</td></tr><tr><td><textarea id="ChatRoom" rows="20" cols="40"></textarea></td><td><textarea 
id="Users" rows="20" cols="20"></textarea></td></tr></table> Message:
                <input type="text" id="Message" style="width:230px;" />
<input type="button" onclick="SendMessage();" name="Send"
                    value="Send" />  CMD: 
<input type="text" id="CommandBox" style="width:80px;" /><input type="button" onclick="SendCommand();" 
name="Issue"
                    value="Issue" /><br />
            </td>
            <td valign="bottom"><strong>Socket Events</strong><br /><br />
                Status<br />
                <textarea id="Status" rows="5" cols="30"></textarea>
                <br />
                Data<br />
                <textarea id="Data" rows="5" cols="30"></textarea>
                <br />
                Errors<br />
                <textarea id="Errors" rows="5" cols="30"></textarea></td>
        </tr>
    </table>
    <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" id="flashObject" width="0"
        height="0" codebase="%22%3C/span">%22%3C/span">http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab">
http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab        style="display: hidden">

        <param name="movie" value="javascriptsockets.swf" />
        <param name="quality" value="low" />
        <param name="allowScriptAccess" value="always" />
        <embed src="javascriptsockets.swf" quality="low" width="0" height="0" name="flashObject"

            id="flashObject" align="middle" play="true" loop="false" allowscriptaccess="always"

            type="application/x-shockwave-flash" pluginspage="%22%3C/span">%22%3C/span">http://www.macromedia.com/go/getflashplayer%22%3Cbr%3E">
http://www.macromedia.com/go/getflashplayer"


            style="display: hidden">
          </embed>
    </object>
</body>
</html>"
", 81);
">
">

Socket Server Implementation

I wont go into the full detail of the code, but its a simple async socket server created in C#. It handles the incoming connection requests and sends out responses. The important things to look at is the Sandbox Cross Domain Policy it sends out. Basically flash will request this from your server to make sure its allowed to use your server. The code for this is below.

    
/// <summary>Class for creating a tcp socket listener.</summary>

    class Listener
    {
        #region Variables
        private ManualResetEvent vManualReset = null;
        private Dictionary<Guid, StateObject> vStateObjects = null;
        private List<Guid> vStateIDS = null;
        private Socket vListenerSocket = null;
        #endregion Variables
        #region Properties
        /// <summary>Holds the current state ids.</summary>

        public List<Guid> StateIDS
        {
            get { return vStateIDS; }
            set { vStateIDS = value; }
        }
        /// <summary>Holds all currently working socket stateobject information.</summary>

        internal Dictionary<Guid, StateObject> StateObjects
        {
            get { return vStateObjects; }
        }
        /// <summary>The main listener socket.</summary>

        public Socket ListenerSocket
        {
            get { return vListenerSocket; }
        }
        #endregion Properties
        #region Constructor
        /// <summary>Constructor</summary>

        public Listener()
        {
        }
        #endregion Constructor
        #region Server Methods
        /// <summary>Listen for connections.</summary>

        public void Listen()
        {
            //Declare variables--------------

            IPHostEntry Host = null;
            IPEndPoint EP = null;
            IPAddress IP = null;
            //-------------------------------

            //Set Host and Endpoint----------

            IP = IPAddress.Parse("127.0.0.1");
            if (IPAddress.TryParse(ConfigurationManager.AppSettings["ListeningAddress"], out IP))
            {
                EP = new IPEndPoint(IP, int.Parse(ConfigurationManager.AppSettings["ListeningPort"]));
            }
            else
            {
                Host = (ConfigurationManager.AppSettings["ListeningAddress"] == string.Empty) ?
 Dns.GetHostEntry(ConfigurationManager.AppSettings
["ListeningAddress"]) : Dns.GetHostEntry(Dns.GetHostName());
                EP = new IPEndPoint(Host.AddressList[0], 
int.Parse(ConfigurationManager.AppSettings["ListeningPort"]));
            }
            //-------------------------------

            //Create listener and stateobject holder----------------

            vManualReset = new ManualResetEvent(false);
            vListenerSocket = new Socket(EP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            //------------------------------------------------------

            try
            {
                //Bind Socket and start listening----

                vListenerSocket.Bind(EP);
                vListenerSocket.Listen(int.Parse(ConfigurationManager.AppSettings["TotalAllowedConnections"]));
                //-----------------------------------

                while (true)
                {
                    vManualReset.Reset();
                    vListenerSocket.BeginAccept(new AsyncCallback(ConnectionAccept), vListenerSocket);
                    vManualReset.WaitOne();
                }
            }
            catch { }
            finally
            {
            }
        }
        /// <summary>Accepts the connection and transfers it and calls listening thread to repeat</summary>

        /// <param name="_AR">The async result.</param>

        private void ConnectionAccept(IAsyncResult _AR)
        {
            //Declare Variables-----------

            Socket ListSocket = null;
            Socket CurrentSocket = null;
            StateObject CurrentStateObject = null;
            //----------------------------

            //Set Sockets-----------------

            ListSocket = (Socket)_AR.AsyncState;
            CurrentSocket = ListSocket.EndAccept(_AR);
            //----------------------------

            //Set ManualEvent-------------

            vManualReset.Set();
            //----------------------------

            //Check if there is stateobjects and add to it----------

            if (vStateObjects == null) { vStateObjects = new Dictionary<Guid, StateObject>(); }
            //------------------------------------------------------

            //Check if stateids is null and add to it---------------

            if (vStateIDS == null) { vStateIDS = new List<Guid>(); }
            //------------------------------------------------------

            //Set Current State Object------------

            CurrentStateObject = new StateObject(CurrentSocket, 
int.Parse(ConfigurationManager.AppSettings["BufferSize"]));
            //------------------------------------

            //Add StateObject to generic list-----

            vStateObjects.Add(CurrentStateObject.UniqueID, CurrentStateObject);
            //------------------------------------

            //Add ID------------------------------

            vStateIDS.Add(CurrentStateObject.UniqueID);
            //------------------------------------

            try
            {
                //Start Receiving Data----------------

                CurrentSocket.BeginReceive(CurrentStateObject.Buffer, 0,
 CurrentStateObject.BufferSize, 0, new AsyncCallback(ReadCallback), 
CurrentStateObject);
                //------------------------------------

            }
            catch { CloseSocket(CurrentStateObject); return; }
        }
        /// <summary>Handles the receiving of data from a current socket.</summary>

        /// <param name="_AR">The async result.</param>

        private void ReadCallback(IAsyncResult _AR)
        {
            //Declare Variables-----------

            StateObject CurrentState = null;
            int BytesRead = 0;
            string Command = string.Empty;
            string r = string.Empty;
            bool first = false;
            Guid[] CurrentIDS = new Guid[vStateIDS.Count];
            //----------------------------

            //Copy IDS--------------------

            vStateIDS.CopyTo(CurrentIDS);
            //----------------------------

            //Set StateObject-------------

            CurrentState = (StateObject)_AR.AsyncState;
            //----------------------------

            //Get the total bytes read----

            try
            {
                BytesRead = CurrentState.WorkSocket.EndReceive(_AR);
            }
            catch { CloseSocket(CurrentState); return; }
            //----------------------------

            if (BytesRead > 0)
            {
                //Check for XML Domain Policy Request-------

                Command = Encoding.Default.GetString(CurrentState.Buffer, 0, BytesRead);
                //------------------------------------------

                switch (Command.ToUpper())
                {
                    case "<POLICY-FILE-REQUEST/>\0":
                        //Send Cross Domain Policy--------------------------------------------

                        XmlDocument XD = new XmlDocument();
                        Configuration Config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                        ConfigurationSection CS = (ConfigurationSection)Config.GetSection("CrossDomainPolicy/Policy");
                        XD.LoadXml(CS.SectionInformation.GetRawXml());
                        XmlNode XN = XD.SelectSingleNode("Policy");
                        Send(XN.InnerText.Replace("\r\n", "") + "\0", CurrentState, true);
                        //--------------------------------------------------------------------

                        break;
                    default:
                        string[] cmd = Command.Split(':');
                        switch (cmd[0].ToUpper())
                        {
                            case "MESSAGE":
                                foreach (Guid ID in CurrentIDS)
                                {
                                    if (ID != CurrentState.UniqueID)
                                    {
                                        if (vStateObjects.ContainsKey(ID))
                                        {
                                            Send("{CMD:'MESSAGE', STAT:'<"
 + CurrentState.WorkSocket.RemoteEndPoint.ToString().Split(':')[0] + "> " + cmd
[1].Trim() + "'}", vStateObjects[ID], false);
                                        }
                                        else
                                        {
                                            vStateIDS.Remove(ID);
                                        }
                                    }
                                }
                                Send("{CMD:'MESSAGE', STAT:'<" + 
CurrentState.WorkSocket.RemoteEndPoint.ToString().Split(':')[0] + "> " + cmd[1].Trim() + 
"'}", CurrentState, false);
                                break;
                            case "NICKNAME": Send("Your nickname has been changed to" + cmd[1], CurrentState, false); break;
                            case "LOGOUT":
                                foreach (Guid ID in CurrentIDS)
                                {
                                    if (ID != CurrentState.UniqueID)
                                    {
                                        if (vStateObjects.ContainsKey(ID))
                                        {
                                            if (first) { r += "\n"; } else { first = true; }
                                            r += vStateObjects[ID].WorkSocket.RemoteEndPoint.ToString().Split(':')[0];
                                        }
                                        else
                                        {
                                            vStateIDS.Remove(ID);
                                        }
                                    }
                                }
                                foreach (Guid ID in CurrentIDS)
                                {
                                    if (ID != CurrentState.UniqueID)
                                    {
                                        if (vStateObjects.ContainsKey(ID))
                                        {
                                            Send("{CMD:'LOGOUT', DATA:'" + r + "',STAT:'User Disconnected - " +
 
CurrentState.WorkSocket.RemoteEndPoint.ToString().Split(':')[0] + "'}", vStateObjects[ID], false);
                                        }
                                        else
                                        {
                                            vStateIDS.Remove(ID);
                                        }
                                    }
                                }
                                Send("{CMD:'LOGOUT', DATA:'" + r + "',STAT:'User Disconnected - " +
 CurrentState.WorkSocket.RemoteEndPoint.ToString().Split
(':')[0] + "'}", CurrentState, true);
                                break;
                            case "USERS" :
                                foreach (Guid ID in CurrentIDS)
                                {
                                    if (vStateObjects.ContainsKey(ID))
                                    {
                                        if (first) { r += ","; } else { first = true; }
                                        r += vStateObjects[ID].WorkSocket.RemoteEndPoint.ToString().Split(':')[0];
                                    }
                                    else
                                    {
                                        vStateIDS.Remove(ID);
                                    }
                                }
                                foreach (Guid ID in CurrentIDS)
                                {
                                    if (ID != CurrentState.UniqueID)
                                    {
                                        if (vStateObjects.ContainsKey(ID))
                                        {
                                            Send("{CMD:'USERLIST', DATA:'" + r + "', STAT:'Welcome User - " + 

CurrentState.WorkSocket.RemoteEndPoint.ToString().Split(':')[0] + "'}", vStateObjects[ID], false);
                                        }
                                        else
                                        {
                                            vStateIDS.Remove(ID);
                                        }
                                    }
                                }
                                Send("{CMD:'USERLIST', DATA:'" + r + "',STAT:'Welcome User - "
 + CurrentState.WorkSocket.RemoteEndPoint.ToString().Split
(':')[0] + "'}", CurrentState, false);
                                break;
                        }
                        break;
                }
                try
                {
                    //Get more data from socket-----------------

                    CurrentState.WorkSocket.BeginReceive(CurrentState.Buffer, 0, CurrentState.BufferSize,
 0, new AsyncCallback(ReadCallback), CurrentState);
                    //------------------------------------------

                }
                catch { CloseSocket(CurrentState); return; }
            }
            else
            {
                //Close the connection and remove the object-----

                CloseSocket(CurrentState);
                //-----------------------------------------------

            }
        }
        /// <summary>Closes the socket and disposes of the state object and removes it from

 the generic dictonary.</summary>
        /// <param name="_StateObject">The stateobject to remove.</param>
        private void CloseSocket(StateObject _StateObject)
        {
            //Declare Variables---------------
            Guid UniqueID = _StateObject.UniqueID;
            //--------------------------------
            //Close Connection----------------
            if (_StateObject.WorkSocket != null)
            {
                try
                {
                    _StateObject.WorkSocket.Shutdown(SocketShutdown.Both);
                    _StateObject.WorkSocket.Close();
                }
                catch { }
                finally
                {
                    _StateObject.WorkSocket = null;
                    _StateObject = null;
                }
            }
            //--------------------------------
            //Remove object from dictonary----
            vStateIDS.Remove(UniqueID);
            vStateObjects.Remove(UniqueID);
            //--------------------------------
        }
        /// <summary>Send string data to the current socket.</summary>
        /// <param name="_StringData">The string to send.</param>
        /// <param name="_StateObject">The stateobject to send the string to.</param>
        /// <param name="_CloseConnection">Closes the connection.</param>
        public void Send(string _StringData, StateObject _StateObject, bool _CloseConnection)
        {
            Send(Encoding.Default.GetBytes(_StringData), _StateObject, _CloseConnection);
        }
        /// <summary>Send string data to the current socket.</summary>
        /// <param name="_ByteData">The byte data to send.</param>
        /// <param name="_StateObject">The stateobject to send the data to.</param>
        /// <param name="_CloseConnection">Closes the connection.</param>
        public void Send(byte[] _ByteData, StateObject _StateObject, bool _CloseConnection)
        {
            _StateObject.Terminate = _CloseConnection;
            try
            {
                _StateObject.WorkSocket.BeginSend(_ByteData, 0, _ByteData.Length, 0,
 new AsyncCallback(SendCallback), _StateObject);
            }
            catch { CloseSocket(_StateObject); return; }
        }
        /// <summary>Handles the send callback.</summary>
        /// <param name="ar">The async result.</param>
        private void SendCallback(IAsyncResult _AR)
        {
            //Declare Variables-----------
            StateObject CurrentState = null;
            int BytesSent = 0;
            //----------------------------
            //Set StateObject-------------
            CurrentState = (StateObject)_AR.AsyncState;
            //----------------------------
            try
            {
                BytesSent = CurrentState.WorkSocket.EndSend(_AR);
            }
            catch { CloseSocket(CurrentState); return; }
            //Check to see if terminated---
            if (CurrentState.Terminate) { CloseSocket(CurrentState); }
            //-----------------------------
        }
        #endregion Server Methods
    }

The full code can be found in the source files. You can create a socket server however you desire with whatever language. As long as it handles requests. You can even choose to use an HTTP Web Server if you want. All depends on what you want to code for.

Conclusion

Well that concludes my FreeDOM tutorial. Please check back for updates as I create more apps using this technique. Have Fun! Enjoy!

History

  • December 15, 2007 - FWS - FreeDOM Web Server Version 1.0b Created
  • December 13, 2007 - Creating a custom open source Unix web server in C to handle FreeDOM projects.
  • November 15, 2007 - Bought a domain name for FreeDOM. WWW.FDOM.US
  • November 07, 2007 - Created ActionScript Tutorial
  • November 05, 2007 - Created SourceForge Project for FreeDOM
  • November 02, 2007 - Added Javascript Sockets Source Code and Added a WikiPedia entry for FreeDOM(programming)
  • November 01, 2007 - Added FreeDOM Ping Example and Source Code
  • October 30, 2007 - Version 1.0A

External Links

Terms and Conditions For Use, Copy, Distribution, and Modification

THIS CODE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS CODE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

VectorX


A little bit about me? Well I love to program, draw and invent new concepts. I am currently building a new programming language called master c and i'm also finishing up my new web server called FWS.

http://www.codevendor.com
Occupation: Architect
Company: The Code Project
Location: United States United States

Other popular Ajax and Atlas articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 42 (Total in Forum: 42) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralUselessmemberJ.Ghassan1:02 15 May '08  
GeneralNo longer needed - see SilverLightmemberDewey16:26 29 Apr '08  
GeneralGreat articlemvpDaniel Vaughan