ConnectPool.cs
6.21 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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
}
}