Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

.NET TCP Connection Pooling

3.56/5 (8 votes)
5 Apr 2009CPOL2 min read 65.9K   2K  
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)