/// <summary>
        /// Called by the OS when new data arrives. If the connection is closed does nothing, else
        /// gets the SocketState and calls the callback function provided by the SocketState.
        /// </summary>
        public static void ReceiveCallback(IAsyncResult stateAsArObject)
        {
            SocketState state = (SocketState)stateAsArObject.AsyncState;

            int bytesRead = 0;

            try
            {
                bytesRead = state.GetSocket().EndReceive(stateAsArObject);
            }
            catch (SocketException e)
            {
                state.HasError     = true;
                state.ErrorMessage = e.Message;
                // invoke client delegate so it can take whatever action it needs with an error
                state.InvokeNetworkAction(state);
            }
            catch (ObjectDisposedException e)
            {
                state.HasError     = true;
                state.ErrorMessage = e.Message;
                // invoke client delegate so it can take whatever action it needs with an error
                state.InvokeNetworkAction(state);
            }

            // If the socket is still open
            if (bytesRead > 0)
            {
                string theMessage = Encoding.UTF8.GetString(state.GetMessageBuffer(), 0, bytesRead);
                // Append the received data to the growable buffer.
                // It may be an incomplete message, so we need to start building it up piece by piece
                state.GetStringBuilder().Append(theMessage);

                // Instead, just invoke the client's delegate, so it can take whatever action it desires.
                state.InvokeNetworkAction(state);
            }
        }
 /// <summary>
 /// Takes in a SocketState object, state, and loads the buffer with data coming from the socket.
 /// </summary>
 public static void GetData(SocketState state)
 {
     try
     {
         state.GetSocket().BeginReceive(state.GetMessageBuffer(), 0, state.GetMessageBuffer().Length, SocketFlags.None, ReceiveCallback, state);
     }
     catch (SocketException e)
     {
         // put the state object in a state of error with the given message
         state.HasError     = true;
         state.ErrorMessage = e.Message;
         // invoke client delegate so it can take whatever action it needs with an error
         state.InvokeNetworkAction(state);
     }
 }
        /// <summary>
        /// This function is "called" by the operating system when the remote site acknowledges connect request
        /// </summary>
        /// <param name="ar"></param>
        private static void ConnectedCallback(IAsyncResult ar)
        {
            //pull SocketState object from the IAsyncResult object, ar
            SocketState state = (SocketState)ar.AsyncState;

            try
            {
                // Complete the connection.
                state.GetSocket().EndConnect(ar);
            }
            catch (Exception e)
            {
                state.HasError     = true;
                state.ErrorMessage = e.Message;
            }

            state.InvokeNetworkAction(state);
        }
        /// <summary>
        /// This function is "called" by the operating system when a remote
        /// connection request comes in.
        ///
        /// AcceptNewClient creates a new socket and saves it in a SocketState
        /// object then invokes the NetworkAction delegate stored by the
        /// parameter ar and continues the event loop.
        /// </summary>
        public static void AcceptNewClient(IAsyncResult ar)
        {
            // extract the ConnectionState from ar
            ConnectionState cs = (ConnectionState)ar.AsyncState;

            // extract the socket from the TCP listener
            Socket socket = cs.GetTcpListener().EndAcceptSocket(ar);

            // save the socket along with a network action
            SocketState ss = new SocketState(socket, -1);

            ss.SetNetworkAction(cs.GetNetworkAction());

            // invoke the network action and pass it our new socket state
            ss.InvokeNetworkAction(ss);

            //continue the event loop
            cs.GetTcpListener().BeginAcceptSocket(AcceptNewClient, cs);
        }
        /// <summary>
        /// Called by the OS when the socket connects to the server.
        /// </summary>
        public static void ConnectedToServer(IAsyncResult stateAsArObject)
        {
            SocketState state = (SocketState)stateAsArObject;

            state.InvokeNetworkAction(state);
        }