65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET TCP 连接池

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.56/5 (8投票s)

2009年4月5日

CPOL

2分钟阅读

viewsIcon

67114

downloadIcon

2016

通过连接池提高 TCP 连接性能。

引言

对于任何处理客户端请求的软件,在某个时刻,都必须存在一个持久点来存储所有与客户端相关的数据。这些存储可以是任何东西(数据库、大型机、文件等)。如果此软件需要使用并发请求访问这些存储,并且知道打开连接会消耗内存和 CPU,该怎么办?连接池是打开的和可重用的连接的容器。它将帮助您节省内存和 CPU 时间。它还将帮助您管理连接。

背景

由于我们在本例中使用 TCP 协议,因此您应该了解 C# 中的基本 TCP 实现。您还应该熟悉 System.Collection.Generic 命名空间和 .NET 框架。

使用代码

本文描述了连接池机制的自定义实现;我们有两个主要类:ConnectionPoolCustomSocket

CustomSocket 是一个简单的 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 是连接池机制的操作管理器,它包含以下内容

InitializeConnectionPool 函数初始化连接池,其中 hostIpAddress 是目标 TCP 服务器,hostPortNumber 是目标 TCP 服务器访问端口,而 minConnection 表示要创建的最小连接数。由于我们可以创建默认数量的连接,因此控制新连接的创建非常重要,否则我们会得到溢出。maxConnections 表示要创建的最大数量;如果超过该值,将抛出异常。

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());
}

GetSocket 函数返回一个连接对象,具有两种流程。如果池中有可用的连接,它将弹出一个连接;如果没有,它将创建一个新连接。

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();
}

PutSocket 函数负责处理连接的释放;如果达到最大限制,则将释放连接;否则,它将被排队。

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());
        }
    }
}

当抛出异常时,将调用此方法以通知连接池已释放套接字

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

要使用此组件,请执行以下操作

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

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

注释

每个套接字都有一个过期时间;如果过期,则将释放该套接字。

历史

  • 版本 1.0。
© . All rights reserved.