Click here to Skip to main content
15,868,016 members
Articles / Programming Languages / C#

.NET TCP Connection Pooling

Rate me:
Please Sign up or sign in to vote.
3.56/5 (8 votes)
5 Apr 2009CPOL2 min read 64.6K   2K   39   4
Pooling TCP connections to increase performance.

Introduction

For any software that handles client requests, at some point, there must be a persistent point where all data related to the clients are stored. Those storages can be any thing (database, mainframes, files etc.). What if this software needs to access those storages with concurrent requests, knowing that opening a connection is memory and CPU consuming? A Connection Pool is a container of open and reusable connections. It will help you save both memory and CPU time. Also, it will help you in managing connections.

Background

Since we are using the TCP protocol in this example, you should know about basic TCP implementation in C#. You should also be familiar with the System.Collection.Generic namespace and the .NET framework.

Using the code

This article describes a custom implementation for a connection pooling mechanism; we have two main classes: ConnectionPool and CustomSocket.

CustomSocket is a representation for a simple TCPClient.

C#
public class CustomSocket:TcpClient
{
    private DateTime _TimeCreated;

    public DateTime TimeCreated
    {
        get { return _TimeCreated; }
        set { _TimeCreated = value; }
    }

    public CustomSocket(string host,int port)
        : base(host,port)
    {
        _TimeCreated = DateTime.Now;
    }
}

ConnectionPool is the operation manager for the pooling mechanism, and it contains the following:

The InitializeConnectionPool function initializes the connection pool, where hostIpAddress is the destination TCP server, hostPortNumber is the destination TCP server access port, while minConnection represents the minimum connection to be created. Since we can create a default number of connections, it is important to control the creation of a new connection or we will get an overflow. maxConnections represents the maximum number to be created; an exception will be thrown if the value is exceeded.

C#
public static void InitializeConnectionPool(string hostIPAddress, 
              int hostPortNumber, int minConnections, int maxConnections)
{
    POOL_MAX_SIZE = maxConnections;
    POOL_MIN_SIZE = minConnections;
    hostIP = hostIPAddress;
    hostPort = hostPortNumber;
    availableSockets = new Queue<CustomSocket>();
     for(int i=0 ; i < minConnections ; i++)
     {
         CustomSocket cachedSocket = OpenSocket();
         PutSocket(cachedSocket);
     }
        
     Initialized = true;
      
     System.Diagnostics.Trace.WriteLine("Connection Pool is initialized" + 
            " with Max Number of " +
            POOL_MAX_SIZE.ToString() + " And Min number of " + 
            availableSockets.Count.ToString());
}

The GetSocket function returns a connection object with two flows. If there is an available connection in the pool, it will pop a connection; if not, it will create a new connection.

C#
public static CustomSocket GetSocket()
{
  if (ConnectionPool.availableSockets.Count > 0)
  {
     lock (availableSockets)
     {
       CustomSocket socket = null;
       while (ConnectionPool.availableSockets.Count > 0)
       {
         socket = ConnectionPool.availableSockets.Dequeue();

         if (socket.Connected)
         {
            System.Diagnostics.Trace.WriteLine("Socket Dequeued -> Pool size: " +
                               ConnectionPool.availableSockets.Count.ToString());

            return socket;
          }
          else
          {
              socket.Close();
              System.Threading.Interlocked.Decrement(ref SocketCounter);
              System.Diagnostics.Trace.WriteLine("GetSocket -- Close -- Count: " + 
                                                 SocketCounter.ToString());
          }
     }
  }
  return ConnectionPool.OpenSocket();
}

The PutSocket function is responsible for handling the disposing of the connection; if the maximum limit is reached, then the connection will be disposed; else, it will be queued.

C#
public static void PutSocket(CustomSocket socket)
{
    lock (availableSockets)
    {
        TimeSpan socketLifeTime = DateTime.Now.Subtract(socket.TimeCreated);
        if (ConnectionPool.availableSockets.Count < 
            ConnectionPool.POOL_MAX_SIZE && socketLifeTime.Minutes < 2)
        // Configuration Value
        {
            if (socket != null)
            {
                if (socket.Connected)
                {
                    ConnectionPool.availableSockets.Enqueue(socket);

                    System.Diagnostics.Trace.WriteLine(
                      "Socket Queued -> Pool size: " + 
                      ConnectionPool.availableSockets.Count.ToString());
                }
                else
                {
                    socket.Close();
                }
            }
        }
        else
        {
            socket.Close();
            System.Diagnostics.Trace.WriteLine("PutSocket - Socket is forced " + 
                               "to closed -> Pool size: " +  
                               ConnectionPool.availableSockets.Count.ToString());
        }
    }
}

This method is called whenever an exception is thrown to inform the connection pool that a socket has been disposed:

C#
public static void PopulateSocketError()
{
    System.Threading.Interlocked.Decrement(ref SocketCounter);
    System.Diagnostics.Trace.WriteLine("Populate Socket Error host " + 
           "Connections count: " + SocketCounter.ToString());
}

To use this component, do as follows:

C#
ConnectionPool.InitializeConnectionPool(hostIPAddress, hostPortNumber, 
               minConnections, maxConnections);
try
{
   // Get Socket
   CustomSocket = ConnectionPool.GetSocket();
   // Do Something

   // Return socket
   ConnectionPool.PutSocket();
}
catch(Exception)
{
    ConnectionPool.PopulateSocketError();
}

Notes

Every socket has an expiry time; if expired, the socket will be disposed.

History

  • Version 1.0.

License

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


Written By
Program Manager
Jordan Jordan
Self-motivated, creative and results-driven technology executive who is well versed and experienced in leveraging an end-to-end, holistic vision of business objectives to drive full technology / business alignment.

Skilled in grasping business needs and sudden market demand’s shifts by diving into latest business / technology trends, selecting the best fit business model / technology to create a positive reflection on revenue. His multifaceted approach has enabled him to deliver key solutions across a wide range of disciplines including design, development, UX / UI, Business Intelligence.

Technical Specialties are in .Net, Java, Spring Boot, Maven, MS SQL, Oracle, Postgesql, Redis, Javascript, Bootstrap, Angular 2.

Comments and Discussions

 
GeneralMy vote of 2 Pin
frazGJF30-Oct-14 18:26
frazGJF30-Oct-14 18:26 
Questiongood Pin
Member 1045917625-Dec-13 22:49
Member 1045917625-Dec-13 22:49 
GeneralMy vote of 5 Pin
Wilson Edgar28-Sep-12 5:21
professionalWilson Edgar28-Sep-12 5:21 
Perfect for small projects.
GeneralPerformances Pin
DJAlexxstyle19-Mar-11 11:12
DJAlexxstyle19-Mar-11 11:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.