Archive

Posts Tagged ‘Socket’

Dotnet Async Socket Server – 5.Pool, buffer and disposer

April 20, 2010 Leave a comment

 

Introduction

This article is 5th part of the Dotnet Async Socket Server series. In this part, we will implement the AsyncArgsPool and the BufferManager class to make our echo server more efficiently in memory management.

I think it is good to see the Architecture part of this series before start this part.

 

The AsyncArgsPool class (the final edition)

We can get the original source form this MSDN part.

I edited the original source a little bit and added the disposing implementation. Of course, this snippet is based on the MSDN dispose pattern.

...

namespace SuWare.Net.Sockets
{
    public class AsyncArgsPool : IDisposable
    {

        private Stack<SocketAsyncEventArgs> pool;

        ...

        /// <summary>
        /// Disposer of this object.
        /// </summary>
        /// <param name="disposing">disposing option</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    //TBD: Dispose managed resources
                    foreach (SocketAsyncEventArgs element in this.pool)
                    {
                        element.Dispose();
                    }
                }

                //TBD: Release unmanaged resources
            }
            this.disposed = true;
        }

        #endregion
    }
}

 

The BufferManager class (the final edition)

We can also get the original source from this MSDN part.

I also edited the original source a little bit and added the disposing implementation.

...

namespace SuWare.Net.Sockets
{
    public class BufferManager : IDisposable
    {


        ...

        /// <summary>
        /// Disposer of this object.
        /// </summary>
        /// <param name="disposing">disposing option</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    //TBD: Dispose managed resources
                    this.buffer = null;
                    this.freeIndexPool = null;
                }

                //TBD: Release unmanaged resources
            }
            this.disposed = true;
        }

        #endregion
    }
}

 

The SocketListener refactoring

To use the pooling and the buffer management, the prior socket listener should be edited little bit. The poolSize parameter in the constructor means the limit of concurrent maximum connections.

...

namespace SuWare.Net.Sockets
{
    public class SocketListener : IDisposable
    {
        ...
        private readonly int poolSize;
        private AsyncArgsPool readwritePool;
        private BufferManager bufferManager;

        ...

        public SocketListener(IPAddress address,int port,int backlog,int poolSize,int bufferSize)
        {
            ...
            this.poolSize = poolSize;
            this.bufferSize = bufferSize;
            ...

            this.readwritePool = new AsyncArgsPool(poolSize);
            this.bufferManager = new BufferManager(poolSize, bufferSize);
        }

        ...

        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            ...

            if (e.SocketError == SocketError.Success)
            {
                //Checkout Buffer with pool and buffermanager
                SocketAsyncEventArgs messageArgs = this.readwritePool.CheckOut();
                this.bufferManager.CheckOut(messageArgs);

                Connection connection = new Connection(
                    this.bufferSize, e.AcceptSocket, messageArgs, this.RemoveConnection,
                    this.OnDisconnected, this.OnReceived, this.OnSent);

                ...
            }

            this.StartAccept();
        }

        ...
    }
}

 

The Echo server refactoring

Let’s edit the echo server to pass the poolSize parameter.

...

namespace SuWare.Sample.EchoServer
{
    class Program
    {
        static void Main(string[] args)
        {
            ...

            SocketListener server = new SocketListener(IPAddress.Parse("127.0.0.1"), 4096, 10,2000, 4096);
            ...
        }

        ...
    }

 

Dispose Implement

It is good to implement IDispose interface for the SocketListener, the Connection and the SocketClient class.

This is the dispose method of the SocketListener class.

        private void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    this.StopListener();
                    if (this.acceptArgs != null)
                    {
                        this.acceptArgs.Dispose();
                        this.acceptArgs = null;
                    }
                    if (this.readwritePool != null)
                    {
                        this.readwritePool.Dispose();
                        this.readwritePool = null;
                    }
                    if (this.bufferManager != null)
                    {
                        this.bufferManager = null;
                    }
                }

                disposed = true;
            }
        }

 

You can download the source of this part at here.

Advertisements

Dotnet Async Socket Server – 4.Echo server

April 19, 2010 4 comments

Introduction

In this part, we will make the basic echo messaging logics on the prior bare bone connection components.

Contents of this series

 

Overview

I’ll extend the existing the SocketListener, the Connection and the SocketClient classes to support sending and receiving messages. Also, I will add a helper class for the SocketAsyncEventArgs to simplify my codes.

Let’s view below diagram that describes the duplex messaging process. Be aware we will not implement the casting function in this part (Step A,B and C).

The Connection class

When this connection object is instantiated by the socket listener, the listener class may pass a raw SocketAsyncEventArgs instance with buffer setting. Be aware we will replace this simple assigning code to the pooling and buffering code from the AsyncArgsPool and the BufferManager classes in the future part of this series.

    public class SocketListener
    {
        ...


        private void ProcessAccept(SocketAsyncEventArgs e)
        {
            ...

            if (e.SocketError == SocketError.Success)
            {
                //Connection Create with passing a raw SocketAsyncEventArgs with buffer setting
                SocketAsyncEventArgs messageArgs = new SocketAsyncEventArgs();
                byte[] buff = new byte[this.bufferSize];
                messageArgs.SetBuffer(buff, 0, buff.Length);
                Connection connection = new Connection(
                    e.AcceptSocket, this.OnDisconnected,this.OnReceived, this.OnSent, messageArgs, this.bufferSize);

                ...
            }

            this.StartAccept();
        }
    }

Let’s see the connection class that has two SocketAsyncEventArgs. In this part, we will use only the messageArgs object to service listening request from clients and to responding those requests. When this connection class is instantiated, the StartRecieve() method is also started ( 1st step of the above diagram). The above StartRecieve()  method will be re- started after execution of the ProcessSent callback handler for response ( 6th step of the above diagram).

...

namespace SuWare.Net.Sockets
{
    public class Connection
    {
        ...
        private readonly int offset;
        private readonly int bufferSize;

        ...
        private Action&lt;SocketAsyncEventArgs&gt; onReceived;
        private Action&lt;SocketAsyncEventArgs&gt; onSent;

        public Connection(
            Socket socket,Action&lt;EndPoint&gt; onDisconnected,Action&lt;SocketAsyncEventArgs&gt; onReceived, 
            Action&lt;SocketAsyncEventArgs&gt; onSent, SocketAsyncEventArgs messageArgs, int bufferSize)
        {
            ...

            this.offset = messageArgs.Offset;
            this.bufferSize = bufferSize;

            ...

            this.onReceived = onReceived;
            this.onSent = onSent;
            ...

            this.StartReceive();
        }

        private void StartReceive()
        {
            if (this.socket.Connected)
            {
                if (!socket.ReceiveAsync(this.messageArgs))
                {
                    this.ProcessMessage(this.messageArgs);
                }
            }
        }

        ...
    }
}

Let’s see the other added methods to the prior version. In the latest version, we didn’t implement the ProcessMessage(…) method. See the implemented the “//implementing messaging operation” section which controls the toggle messaging function.

...

namespace SuWare.Net.Sockets
{
    public class Connection
    {
        ...

        private void Message_Completed(object sender, SocketAsyncEventArgs e)
        {
            this.ProcessMessage(e);
        }

        private void ProcessMessage(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred &gt; 0 &amp;&amp; e.SocketError == SocketError.Success)
            {
                //implementing messaging operation
                switch (e.LastOperation)
                {
                    case SocketAsyncOperation.Receive:
                        this.ProcessReceive(e);
                        break;
                    case SocketAsyncOperation.Send:
                        this.ProcessSent(e);
                        break;
                    default:
                        throw new ArgumentException(&quot;The last operation completed on the socket was not a receive or send&quot;);
                }
            }
            else
            {
                this.CloseClientSocket();
            }
        }

        private void ProcessReceive(SocketAsyncEventArgs e)
        {
            //In this step, user can set sending buffer to the messageargs instance setting onReceived delegate.
            if (this.onReceived != null)
            {
                this.onReceived(e);
            }

            //response to the client socket
            lock (this)
            {
                if (!this.socket.SendAsync(e))
                {
                    this.ProcessSent(e);
                }
            }
        }

        private void ProcessSent(SocketAsyncEventArgs e)
        {
            if (this.onSent != null)
            {
                this.onSent(e);
            }

            //Reset the buffer of the messageargs object to pre-fixed buffer setting
            //In later, this.offset will be the cursor of the one large buffer of the Buffer Manager
            e.SetBuffer(this.offset, this.bufferSize);
            this.StartReceive();

        }

        ...
    }
}

The SocketListener class

Adding two action delegators for messaging is the main additional task.

...

namespace SuWare.Net.Sockets
{
    public class SocketListener
    {
        ...

        public Action&lt;SocketAsyncEventArgs&gt; OnReceived;
        public Action&lt;SocketAsyncEventArgs&gt; OnSent;

	...
    }
}

The SocketClient class

I added two more SocketAsyncEventArgs and two action delegates for messaging. The initialing process was added in the constructor.

...

namespace SuWare.Net.Sockets
{
    public class SocketClient
    {
        ...
        private SocketAsyncEventArgs sendArgs;
        private SocketAsyncEventArgs receiveArgs;

        ...
        public Action&lt;SocketAsyncEventArgs&gt; OnSent;
        public Action&lt;SocketAsyncEventArgs&gt; OnReceive;

        public SocketClient(int bufferSize)
        {
            ...

            this.sendArgs = new SocketAsyncEventArgs();
            this.sendArgs.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(Send_Completed);
            this.sendArgs.UserToken = this.socket;

            this.receiveArgs = new SocketAsyncEventArgs();
            this.receiveArgs.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(Receive_Completed);
            this.receiveArgs.SetBuffer(new byte[bufferSize], 0, bufferSize);
            this.receiveArgs.UserToken = this.socket;
        }

        ...
    }
}

We will use the added send and receive functions of below code snippets.

...

namespace SuWare.Net.Sockets
{
    public class SocketClient
    {
        ...

        public void Send(string message)
        {
            this.Send(Encoding.UTF8.GetBytes(message));
        }

        public void Send(byte[] buffer)
        {
            ...

            lock (this)
            {
                this.sendArgs.SetBuffer(buffer, 0, buffer.Length);
                if (!this.socket.SendAsync(this.sendArgs))
                {
                    this.Send_Completed(this, this.sendArgs);
                }
            }
        }


        private void ConnectCompleted(object sender, SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                this.StartReceive(this.receiveArgs);

                ...
            }
        }

        private void Send_Completed(object sender, SocketAsyncEventArgs e)
        {
            if ( this.OnSent != null)
            {
                this.OnSent(e);
            }
        }

        private void Receive_Completed(object sender, SocketAsyncEventArgs e)
        {
            ...

            if (this.OnReceive != null)
            {
                this.OnReceive(e);
            }

            this.StartReceive(e);
        }

        private void StartReceive(SocketAsyncEventArgs e)
        {
            ...

            lock (this)
            {
                if (!this.socket.ReceiveAsync(e))
                {
                    this.Receive_Completed(this,e);
                }
            }
        }

        ...
    }
}

The Echo Server

Let’s add the action delegators to assign the messaging handlers of the socket listener.

...

namespace SuWare.Sample2.EchoServer
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(&quot;Press enter key to start server&quot;);
            Console.ReadLine();

            SocketListener server = new SocketListener(IPAddress.Parse(&quot;127.0.0.1&quot;), 4096, 10, 4096);
            ...
            server.OnReceived = new Action&lt;SocketAsyncEventArgs&gt;(OnReceived);
            server.OnSent = new Action&lt;SocketAsyncEventArgs&gt;(OnSent);
            ...
        }

        ...

        static void OnReceived(SocketAsyncEventArgs e)
        {
            string rcvMsg = e.GetString();//extention helper method
            LogPrint(&quot;Message Received&quot;, rcvMsg);

            //Setting up new buffer to the messageArgs before sending is very important.
            e.CopyToArgs(&quot;Echo:&quot; + rcvMsg);//extention helper method
        }

        static void OnSent(SocketAsyncEventArgs e)
        {
            LogPrint(&quot;Message Sent&quot;, e.GetString());
        }

        ...
    }
}

The AsyncArgsExtension helper class

To get a clean code, it is good to use the following extension helper class for the SocketAsyncEventArgs. Check the Buffer.BlockCopy(…) in the below code, that provides better performance than the Array.Copy(…).

...

namespace SuWare.Net.Sockets
{
    public static class AsyncArgsExtension
    {

        public static string GetString(this SocketAsyncEventArgs args)
        {
            return GetString(args, Encoding.UTF8);
        }

        public static string GetString(this SocketAsyncEventArgs args, Encoding encode)
        {
            return encode.GetString(args.Buffer, args.Offset, args.BytesTransferred);
        }

        public static byte[] CopyFromArgs(this SocketAsyncEventArgs args)
        {
            byte[] buff = new byte[args.BytesTransferred];
            Buffer.BlockCopy(args.Buffer, args.Offset, buff, 0, buff.Length);
            return buff;
        }

        public static void CopyToArgs(this SocketAsyncEventArgs args, string message)
        {
            CopyToArgs(args, message, Encoding.UTF8);
        }

        public static void CopyToArgs(this SocketAsyncEventArgs args, string message, Encoding encode)
        {
            CopyToArgs(args, encode.GetBytes(message));
        }

        public static void CopyToArgs(this SocketAsyncEventArgs args, byte[] srcBuffer)
        {
            Buffer.BlockCopy(srcBuffer, 0, args.Buffer, args.Offset, srcBuffer.Length);
            args.SetBuffer(args.Offset, srcBuffer.Length);
        }
    }
}

The EchoClient class

Reading the user input in this console app is the main added things.

...

namespace SuWare.Sample2.EchoClient
{
    class Program
    {
        static void Main(string[] args)
        {
            ...
            client.OnSent = new Action&lt;SocketAsyncEventArgs&gt;(OnSent);
            client.OnReceive = new Action&lt;SocketAsyncEventArgs&gt;(OnReceive);
            ...

            Console.WriteLine(&quot;Write a message that you want to send and press enter key&quot;);
            string message = Console.ReadLine();
            client.Send(message);

            ...
        }

        static void Connected(Socket socket)
        {
            LogPrint(&quot;Connected&quot;, socket.RemoteEndPoint.ToString());
        }

        static void Disconnected(EndPoint endpoint)
        {
            LogPrint(&quot;Disconnected&quot;, endpoint.ToString());
        }

        static void OnSent(SocketAsyncEventArgs e)
        {
            LogPrint(&quot;Sent&quot;, e.BytesTransferred.ToString());
        }

        static void OnReceive(SocketAsyncEventArgs e)
        {
            LogPrint(&quot;Received&quot;, e.GetString());
        }

        static void LogPrint(string lable, string message)
        {
            Console.WriteLine(string.Format(&quot;[{0}] {1}&quot;, lable, message));
        }
    }
}

Result

This is the final result of this echo socket solution.

You can download the source of this part at here.

Dotnet Async Socket Server – 3.Bare bone connection

April 16, 2010 3 comments

 

In this part, I will implement the bare bone socket connection with console apps.

 

Contents of this series

 

Overview

It’s good to review the connection diagram in the prior architecture part for understanding this implementation.

 

 

Let’s start a console socket client and a console socket server with connection functions. Check the solution. This contains 1 library and 2 console projects.

 

Click this image to see large class diagram.

 

The base of the Socket Listener class

Let us check the core members of the class. I use 4 action delegates to fire async events instead of event handlers or general delegates.

    public class SocketListener
    {
        private readonly int backlog;
        private readonly int bufferSize;
        private IPEndPoint endPoint;
        private Socket listenSocket;
        private SocketAsyncEventArgs acceptArgs;

        public Action&lt;Socket&gt; OnStarted;
        public Action&lt;IPEndPoint&gt; OnStopped;
        public Action&lt;Socket&gt; OnConnected;
        public Action&lt;EndPoint&gt; OnDisconnected;
        ...

 

In the constructor, the acceptArgs object should be instantiated. It is important to assign a event handler for the accpetArgs’ callback operation. We should implement Accept_Completed handler.

        public SocketListener(IPAddress address,int port,int backlog,int bufferSize)
        {
            ...

            this.acceptArgs = new SocketAsyncEventArgs();
            this.acceptArgs.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(Accept_Completed);
        }
        ...

        private void Accept_Completed(object sender, SocketAsyncEventArgs e)
        {
            this.ProcessAccept(e);
        }

 

These public methods are for starting and stopping the server. If the OnStared and OnStpped actions be not implemented by the console server that uses this listener class, nothing would be happened the server.

        public bool IsRunning()
        {
            return this.listenSocket != null;
        }

        public void StartListener()
        {
            if (IsRunning())
            {
                 throw new InvalidOperationException(&quot;The Server is already running.&quot;);
            }

            this.listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            this.listenSocket.Bind(endPoint);
            this.listenSocket.Listen(backlog);

            if (OnStarted != null)
            {
                OnStarted(this.listenSocket);
            }

            this.StartAccept();
        }

        public void StopListener()
        {
            if (listenSocket == null) return;
            listenSocket.Close();
            listenSocket = null;

            if (OnStopped != null)
            {
                OnStopped(this.endPoint);
            }
        }

 

Accepting methods

If the StartListener method be called, this StartAccept method might be operated. Also this method will be called again by the ProcessAccept method after one acceptance(connection)’s completion.

        private void StartAccept()
        {
            if (this.acceptArgs.AcceptSocket != null)
            {
                this.acceptArgs.AcceptSocket = null;
            }

            if (!this.listenSocket.AcceptAsync(this.acceptArgs))
            {
                this.ProcessAccept(this.acceptArgs);
            }
        }

 

Be aware of the ProcessAccept method. We must pass the OnDisconnected action of this listener to the connection class because we can not catch disconnect event in this current listener. This disconnected event can be fired in the Connection class with messaging functions.

 

Implementing the Connection class

Let’s make the Connection constructor and a completion callback method for the messageArgs.

    public class Connection
    {
        private Socket socket;
        private EndPoint endPoint;
        private SocketAsyncEventArgs messageArgs;

        private Action&lt;EndPoint&gt; onDisconnected;

        public Connection(Socket socket,Action&lt;EndPoint&gt; onDisconnected, SocketAsyncEventArgs messageArgs)
        {
            this.socket = socket;
            this.endPoint = socket.RemoteEndPoint;
            this.onDisconnected = onDisconnected;
            this.messageArgs = messageArgs;
            this.messageArgs.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(Message_Completed);
            this.messageArgs.UserToken = socket;

            this.StartReceive();
        }

        private void Message_Completed(object sender, SocketAsyncEventArgs e)
        {
            this.ProcessMessage(e);
        }
        ...

 

As I said, if the client be disconnected or send 0-length data, the connected client socket should be closed.

        ...
        private void ProcessMessage(SocketAsyncEventArgs e)
        {
            if (e.BytesTransferred &gt; 0 &amp;&amp; e.SocketError == SocketError.Success)
            {
                //not implemented yet
            }
            else
            {
                this.CloseClientSocket();
            }
        }

        private void StartReceive()
        {

            if (this.socket.Connected)
            {
                if (!socket.ReceiveAsync(this.messageArgs))
                {
                    this.ProcessMessage(this.messageArgs);
                }
            }
        }
        ...

 

I think it is good to fire the onDisconnected action inside this CloseClientSocket method, which is originated from the listener,.

        private void CloseClientSocket()
        {
            if (this.socket != null)
            {
                if (this.socket.Connected)
                {
                    try
                    {
                        this.socket.Shutdown(SocketShutdown.Both);
                    }
                    catch (SocketException socketExcept)
                    {
                        throw new SocketException(socketExcept.ErrorCode);
                    }
                    catch { }
                    finally
                    {
                        this.socket.Close();
                        this.socket = null;
                    }
                }

                this.messageArgs.Completed -= Message_Completed;

                if (onDisconnected != null)
                {
                    onDisconnected(this.endPoint);
                }
            }
        }

 

Implementing the Console Socket Server

It is very easy to use the SocketListener.

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(&quot;Press enter key to start server&quot;);
            Console.ReadLine();

            SocketListener server = new SocketListener(IPAddress.Parse(&quot;127.0.0.1&quot;),4096,10,4096);
            server.OnStarted = new Action&lt;Socket&gt;(OnStarted);
            server.OnStopped = new Action&lt;IPEndPoint&gt;(OnStopped);
            server.OnConnected = new Action&lt;Socket&gt;(OnConnected);
            server.OnDisconnected = new Action&lt;EndPoint&gt;(OnDisconnected);
            server.StartListener();

            Console.WriteLine(&quot;Press enter key to stop server&quot;);
            Console.ReadLine();

            server.StopListener();
        }

        static void OnStarted(Socket socket)
        {
            LogPrint(&quot;Server Started&quot;, socket.LocalEndPoint.ToString());
        }

        static void OnStopped(IPEndPoint endPoint)
        {
            LogPrint(&quot;Server Stopped&quot;, endPoint.ToString());
        }

        static void OnConnected(Socket socket)
        {
            LogPrint(&quot;Client Connected&quot;, socket.RemoteEndPoint.ToString());
        }

        static void OnDisconnected(EndPoint endPoint)
        {
            LogPrint(&quot;Client Disconnected&quot;, endPoint.ToString());
        }

        static void LogPrint(string lable, string message)
        {
            Console.WriteLine(string.Format(&quot;[{0}] {1}&quot;, lable, message));
        }
    }

 

Implemeting the basic SocketClient class

The SocketClient is very similar with the listener class. But this use the Socket.ConnectAsync operation instead of the AcceptAsync operation.

    public class SocketClient
    {
        private Socket socket;
        private SocketAsyncEventArgs connectArgs;

        public Action&lt;Socket&gt; Connected;
        public Action&lt;Socket&gt; Disconnected;

        public SocketClient()
        {
            this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            connectArgs = new SocketAsyncEventArgs();
            connectArgs.Completed += new EventHandler&lt;SocketAsyncEventArgs&gt;(ConnectCompleted);
            connectArgs.UserToken = this.socket;
        }

        public bool IsConnected()
        {
            bool result = false;

            if (this.socket != null)
            {
                if (this.socket.Connected)
                {
                    result = true;
                }
            }

            return result;
        }

        public void Connect(IPAddress address, int port)
        {
            lock (this)
            {
                this.connectArgs.RemoteEndPoint = new IPEndPoint(address,port);
                if (!this.socket.ConnectAsync(connectArgs))
                {
                    this.ConnectCompleted(this, this.connectArgs);
                }
            }
        }

        public void Disconnect()
        {
            lock (this)
            {
                if (IsConnected())
                {
                    this.socket.Shutdown(SocketShutdown.Both);
                    this.socket.Close();
                    this.socket = null;
                    this.connectArgs = null;
                }

                if (Disconnected != null)
                {
                    Disconnected(this.socket);
                }
            }
        }

        private void ConnectCompleted(object sender, SocketAsyncEventArgs e)
        {
            if (e.SocketError == SocketError.Success)
            {
                if (Connected != null)
                {
                    Connected(this.socket);
                }
            }
        }
    }

 

Implementing the Console Socket Client

Well, it is also simple to the client making.

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(&quot;Press enter key to connect&quot;);
            Console.ReadLine();

            SocketClient client = new SocketClient();
            client.Connected = new Action&lt;Socket&gt;(Connected);
            client.Disconnected = new Action&lt;Socket&gt;(Disconnected);
            client.Connect(IPAddress.Parse(&quot;127.0.0.1&quot;), 4096);

            Console.WriteLine(&quot;Press enter key to disconnect&quot;);
            Console.ReadLine();
            client.Disconnect();
        }

        static void Connected(Socket socket)
        {
            Console.WriteLine(&quot;Connected&quot;);
        }

        static void Disconnected(Socket socket)
        {
            Console.WriteLine(&quot;Disconnected&quot;);
        }
    }

 

Running the console apps.

Here is the result console apps. Three clients had connected the console server and one client has disconnected.

 

You can download this sample1 source project file at here.

Dotnet Async Socket Server – 2.Architecture

April 14, 2010 4 comments

 

In this part, I will describe the basic concepts and architecture of our socket server we will implement.

Contents of this series

 

Static architecture

Architecture

Let us to see the outlook of our Socket Server component.

  • SocketListener : Connection and messaging management with multiple clients
  • Simple Protocol Codec : By implementing the IProtocol interface, this support decoding(de-serialization) and encoding(serialization) services for the protocol.
  • Event Handler : Handling socket operations and messaging for the Simple Protocol.
  • Fake Service : This provides fake business service with input parameter as decoded object and return object for the encoding resource.
  • Management UI : Through UI Invoke helper class, this UI provides Winform display  and control of the server thread and information.

This server uses two external components.

  • System.Net.Sockets
  • Protobuf-Net : fast and well-designed protobuf implementation for .NET.

This system also will contains 3 communication components.

  • Silverlight Policy Server
  • Silverlight Client : uses the SocketClient class and provides XAML UIs.
  • Winform Client : uses the SocketClient class and provides Winform UIs.

And see some technical operations before the implementation.

 

Listener and Connection

Core classes should have a SocketAsyncEventArgs instances for high-performance async networking in the pure .NET framework.

  • The SocketClient : this use the connectAsync method of the SocketAsyncEventArgs to connect.
  • The SocketListener : this use only the acceptAsync method of the SocketAsyncEventArgs class and may have a list of the Connection object to store the accepted sessions.
  • The Connection class : main role of this is to listen and response for the messaging transactions of each socket session.

Let us to see the following conceptual diagram to understand the basic socket accepting process.

The <2.AcceptAsync> step should be started when the listener start and will be finished in the <4.Accept Completed> step. After creating a connection context, the second step should be restarted to listen another accept request from other socket clients.

 

SocketAsyncEventArgs pool manager and Buffer manager classes

Let us to see the SocketAsyncEventArgs pool manager class at this MSDN section.

“asynchronous socket operations are described by reusable SocketAsyncEventArgs objects allocated and maintained by the application. High-performance socket applications know best the amount of overlapped socket operations that must be sustained.”

Each connection should have a SocketAsyncEventArgs instance for the messaging operations (receive and send). So, the SocketAsyncEventArgs pool manager would provide the instance library of many SocketAsyncEventArgs instances.

We can also see the Buffer manager class on MSDN here.

“This class creates a single large buffer which can be divided up and assigned to SocketAsyncEventArgs objects for use with each socket I/O operation. This enables buffers to be easily reused and guards against fragmenting heap memory.”

 

When each connection is created by the Socket Listener, the listener assigns the total buffer from buffer manager to the connections’ MessageArgs with setting offset and count properties.

Dotnet Async Socket Server– 1.Introduction

April 14, 2010 3 comments

Goal of this series

Using the SocketAsyncEventArgs and the Google’s Protobuf, we can make more fast and flexible socket servers easily.

In this series, I want to show you how to combine the SocketAsyncEventArgs and Protobuf components and to develop pure .net networking server with following subjects.

 

concept

The SocketAsyncEventArgs class

“The System.Net.Sockets.Socket class has been enhanced in Version 3.5 for use by applications that use asynchronous network I/O to achieve the highest performance” … MSDN

The SocketAsyncEventArgs class is a context object for the new System.Net.Sockets.Socket class, which supports non-blocking network I/O with .NET 3.5. The context class provides wrapped IOCP over .NET framework runtime. With this advanced classes, You can make several high performance network applications such as chatting server,on-line game server, messaging middleware or a lightweight HTTP server Over IP networking.

The Google Protobuf

The Google Protobuf is one of the most compact and flexible messaging protocol frameworks in these days. We can easily define business objects and use them with auto-generated Codec(Serialization) classes. The framework is composed two main parts, code generator and runtime libraries. It is formally implemented as C++,Java and Python with documentations, but not as C#. But the framework provides add-on interfaces, so it is implemented as several C# projects like protobuf-csharp-port, protosharp and protobuf-net.

Check the following links you want more information about the framework.

References

We can see more information at below links.