Click here to Skip to main content
Click here to Skip to main content

.NET TCP Connection Pooling

, 5 Apr 2009
Rate this:
Please Sign up or sign in to vote.
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.

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.

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.

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.

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:

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:

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)

About the Author

Wael Al Wirr
Program Manager INVESTBANK
Jordan Jordan
Wael Al Wirr’s Specialties:
•Microsoft BizTalk Server 2004, 2006, 2010
•ASP.Net, C#, ADO.Net and .Net Framework (1.1, 2.0, 3.0, 3.5, 4.0)
•Windows Communication Foundation
•Windows Workflow Foundation
•Windows AppFabric
•ADO.NET Entity Framework
•Microsoft Line Of Business Adapter Framework
•SQL Server 2000, 2005
•Web development
•HTML, XML, XSD, XSLT
•JavaScript
•Database design
•Web Services
•Build, deployment script
•Microsoft Source Safe, Microsoft Team Foundation Server
Follow on   Twitter

Comments and Discussions

 
Questiongood PinmemberMember 1045917625-Dec-13 22:49 
GeneralMy vote of 5 PinmemberWilson Edgar28-Sep-12 5:21 
GeneralPerformances PinmemberDJAlexxstyle19-Mar-11 11:12 

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

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

| Advertise | Privacy | Mobile
Web02 | 2.8.140709.1 | Last Updated 5 Apr 2009
Article Copyright 2009 by Wael Al Wirr
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid