using HslCommunication.ModBus; using System; using System.Collections.Generic; namespace HslCommunication.Algorithms.ConnectPool { /// <summary> /// 一个连接池管理器,负责维护多个可用的连接,并且自动清理,扩容 /// </summary> /// <typeparam name="TConnector">管理的连接类,需要支持IConnector接口</typeparam> /// <remarks> /// 需要先实现 <see cref="IConnector"/> 接口的对象,然后就可以实现真正的连接池了,理论上可以实现任意的连接对象,包括modbus连接对象,各种PLC连接对象,数据库连接对象,redis连接对象,SimplifyNet连接对象等等。下面的示例就是modbus-tcp的实现 /// <note type="warning">要想真正的支持连接池访问,还需要服务器支持一个端口的多连接操作,三菱PLC的端口就不支持,如果要测试示例代码的连接池对象,需要使用本组件的<see cref="ModbusTcpServer"/>来创建服务器对象</note> /// </remarks> /// <example> /// 下面举例实现一个modbus的连接池对象,先实现接口化的操作 /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Algorithms\ConnectPool.cs" region="IConnector Example" title="IConnector示例" /> /// 然后就可以实现真正的连接池了 /// <code lang="cs" source="HslCommunication_Net45.Test\Documentation\Samples\Algorithms\ConnectPool.cs" region="ConnectPoolExample" title="ConnectPool示例" /> /// </example> public class ConnectPool<TConnector> where TConnector : IConnector { #region Constructor /// <summary> /// 实例化一个连接池对象,需要指定如果创建新实例的方法 /// </summary> /// <param name="createConnector">创建连接对象的委托</param> public ConnectPool(Func<TConnector> createConnector) { this.CreateConnector = createConnector; hybirdLock = new HslCommunication.Core.SimpleHybirdLock(); connectors = new List<TConnector>(); timerCheck = new System.Threading.Timer(TimerCheckBackground, null, 10000, 30000); } #endregion #region Public Method /// <summary> /// 获取可用的对象 /// </summary> /// <returns>可用的连接对象</returns> public TConnector GetAvailableConnector() { while (!canGetConnector) { System.Threading.Thread.Sleep(100); } TConnector result = default(TConnector); hybirdLock.Enter(); for (int i = 0; i < connectors.Count; i++) { if (!connectors[i].IsConnectUsing) { connectors[i].IsConnectUsing = true; result = connectors[i]; break; } } if (result == null) { // 创建新的连接 result = CreateConnector(); result.IsConnectUsing = true; result.LastUseTime = DateTime.Now; result.Open(); connectors.Add(result); usedConnector = connectors.Count; if (usedConnector == maxConnector) canGetConnector = false; } result.LastUseTime = DateTime.Now; hybirdLock.Leave(); return result; } /// <summary> /// 使用完之后需要通知管理器 /// </summary> /// <param name="connector">连接对象</param> public void ReturnConnector(TConnector connector) { hybirdLock.Enter(); int index = connectors.IndexOf(connector); if (index != -1) { connectors[index].IsConnectUsing = false; } hybirdLock.Leave(); } #endregion #region Public Properties /// <summary> /// 获取或设置最大的连接数 /// </summary> public int MaxConnector { get { return maxConnector; } set { maxConnector = value; } } /// <summary> /// 获取或设置连接过期的时间,单位秒,默认30秒 /// </summary> public int ConectionExpireTime { get { return expireTime; } set { expireTime = value; } } /// <summary> /// 当前已经使用的连接数 /// </summary> public int UsedConnector { get { return usedConnector; } } #endregion #region Clear Timer private void TimerCheckBackground(object obj) { // 清理长久不用的连接对象 hybirdLock.Enter(); for (int i = connectors.Count - 1; i >= 0; i--) { if ((DateTime.Now - connectors[i].LastUseTime).TotalSeconds > expireTime && !connectors[i].IsConnectUsing) { // 10分钟未使用了,就要删除掉 connectors[i].Close(); connectors.RemoveAt(i); } } usedConnector = connectors.Count; if (usedConnector < MaxConnector) canGetConnector = true; hybirdLock.Leave(); } #endregion #region Private Member private Func<TConnector> CreateConnector = null; // 创建新的连接对象的委托 private int maxConnector = 10; // 最大的连接数 private int usedConnector = 0; // 已经使用的连接 private int expireTime = 30; // 连接的过期时间,单位秒 private bool canGetConnector = true; // 是否可以获取连接 private System.Threading.Timer timerCheck = null; // 对象列表检查的时间间隔 private HslCommunication.Core.SimpleHybirdLock hybirdLock = null; // 列表操作的锁 private List<TConnector> connectors = null; // 所有连接的列表 #endregion } }