view Messaging/Server/Listeners/AsyncSocketListener.cs @ 29:9919ee227c93

msmq added
author adminsh@apollo
date Wed, 21 Mar 2012 22:09:18 +0000
parents 4c0dea4760c5
children
line wrap: on
line source

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Common.Messages;
using GalaSoft.MvvmLight.Messaging;
using Server.Interfaces;

namespace Server.Listeners
{ 
    public class AsyncSocketListener : IListener
    {
        public bool IsListening { get; set; }
        private readonly int _portNumber;

        // Thread signal.
        public static ManualResetEvent AllDone = new ManualResetEvent(false);

        public AsyncSocketListener(int portNumber)
        {
            IsListening = false;
            _portNumber = portNumber;
        }

        public void Start()
        {
            if (IsListening)
            {
                Messenger.Default.Send(new SocketLogMessage() { Body = "Already listening..." });
                return;
            }
            Messenger.Default.Send(new SocketLogMessage() { Body = "Opening listener..." });

            // Data buffer for incoming data.
            var bytes = new Byte[1024];

            // Establish the local endpoint for the socket
            var ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
            var ipAddress = ipHostInfo.AddressList[2];
            var localEndPoint = new IPEndPoint(ipAddress, _portNumber);

            // Create a TCP/IP socket.
            using(var listener = new Socket(
                AddressFamily.InterNetwork,
                SocketType.Stream, 
                ProtocolType.Tcp))
                {

                // Bind the socket to the local endpoint and listen for incoming connections.
                    try
                    {
                        listener.Bind(localEndPoint);
                        listener.Listen(100);
                        IsListening = true;

                        Messenger.Default.Send(new SocketLogMessage() { Body = "Listener opened" });

                        while (IsListening)
                        {
                            // Set the event to nonsignaled state.
                            AllDone.Reset();

                            // Start an asynchronous socket to listen for connections.
                            Messenger.Default.Send(new SocketLogMessage() { Body = "Waiting for a connection..." });

                            listener.BeginAccept(
                                AcceptCallback,
                                listener);

                            // Wait until a connection is made before continuing.
                            AllDone.WaitOne();
                        }

                        if (listener.Connected)
                        {
                            Messenger.Default.Send(new SocketLogMessage() { Body = "Shutting down listener..." });
                            listener.Shutdown(SocketShutdown.Both);

                            Messenger.Default.Send(new SocketLogMessage() { Body = "Disconnecting listener..." });
                            listener.Disconnect(true);
                        }

                    }
                    catch (Exception e)
                    {
                        Messenger.Default.Send(new SocketLogMessage() { Body = e.Message });
                    }
                    finally
                    {
                        Messenger.Default.Send(new SocketLogMessage() { Body = "Connection closed." });
                    }
            }
        }

        public void AcceptCallback(IAsyncResult ar)
        {
            // Signal the main thread to continue.
            AllDone.Set();

            // Get the socket that handles the client request.
            var listener = (Socket) ar.AsyncState;
            var handler = listener.EndAccept(ar);

            // Create the state object.
            var state = new StateObject {WorkSocket = handler};

            handler.BeginReceive(
                state.Buffer, 
                0, 
                StateObject.BufferSize, 
                0,
                ReadCallback, 
                state);
        }

        public void ReadCallback(IAsyncResult ar)
        {
            var content = String.Empty;

            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            var state = (StateObject)ar.AsyncState;
            var handler = state.WorkSocket;

            // Read data from the client socket. 
            var bytesRead = handler.EndReceive(ar);

            if (bytesRead <= 0) return;

            // There  might be more data, so store the data received so far.
            state.Sb.Append(
                Encoding.ASCII.GetString(
                    state.Buffer, 
                    0, 
                    bytesRead));

            // Check for end-of-file tag. If it is not there, read 
            // more data.
            content = state.Sb.ToString();
            if (content.IndexOf("<EOF>") > -1)
            {
                // All the data has been read from the 
                // client. Display it on the console.

                Messenger.Default.Send(
                    new SocketLogMessage() 
                    { 
                        Body = string.Format(
                            "Read {0} bytes from socket. \n Data : {1}",
                            content.Length, 
                            content)
                    });
                
                // Echo the data back to the client.
                Send(handler, "The following message was received: " + content);
            }
            else
            {
                // Not all data received. Get more.
                handler.BeginReceive(
                    state.Buffer, 
                    0, 
                    StateObject.BufferSize, 
                    0,
                    ReadCallback,
                    state);
            }
        }

        private void Send(Socket handler, String data)
        {
            // Convert the string data to byte data using ASCII encoding.
            var byteData = Encoding.ASCII.GetBytes(data);

            // Begin sending the data to the remote device.
            handler.BeginSend(
                byteData, 
                0, 
                byteData.Length, 
                0,
                SendCallback,
                handler);
        }

        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                // Retrieve the socket from the state object.
                var handler = (Socket)ar.AsyncState;

                // Complete sending the data to the remote device.
                var bytesSent = handler.EndSend(ar);

                Messenger.Default.Send(new SocketLogMessage() { Body = string.Format("Sent {0} bytes to client.", bytesSent) });

                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
            catch (Exception e)
            {
                Messenger.Default.Send(new SocketLogMessage() { Body = e.Message });
            }
        }

        public void Stop()
        {
            if (IsListening == false) return;

            Messenger.Default.Send(new SocketLogMessage() { Body = "Closing connection..." });
            IsListening = false;
            AllDone.Set();
        }
    }

    // State object for reading client data asynchronously
    public class StateObject
    {
        // Client  socket.
        public Socket WorkSocket;

        // Size of receive buffer.
        public const int BufferSize = 1024;

        // Receive buffer.
        public byte[] Buffer = new byte[BufferSize];

        // Received data string.
        public StringBuilder Sb = new StringBuilder();
    }
}