C# 连接池开发,多连接高效应用开发,多连接自动维护管理。
本文将使用一个Github开源的组件库技术来实现连接池的操作,应用于一些情况下的频繁的网络连接操作。
github地址:https://github.com/dathlin/HslCommunication 如果喜欢可以star或是fork,还可以打赏支持,打赏请认准源代码项目。
本项目目前支持C#语言和java语言,C#语言的功能比较齐全,java版本的库还在开发及完善中。
nuget地址:https://www.nuget.org/packages/HslCommunication/
github地址:https://github.com/dathlin/HslCommunication 如果喜欢可以star或是fork,还可以打赏支持。
组件的完整信息和API介绍参照:http://www.cnblogs.com/dathlin/p/7703805.html 组件的使用限制,更新日志,都在该页面里面。
为什么需要连接池
首先需要解决这个问题,我们为什么需要连接池,终极目的是是为了高效的数据访问,但并不是所有情况都需要进行连接池搭建的,举几个🌰吧
案例一:你有个后台线程每隔1s钟在读取PLC的数据,你和PLC的交互都在这个线程里面,那么完全是不需要进行连接池的。
案例二:你会在程序的多个线程(包括线程池里面)进行和PLC进行数据交互,频繁的读写操作,如果共用一个连接的性能达不到要求怎么办(通常在无线网络下,一次数据交互在30ms-100ms之间,网络波动较大)?,如果每次操作都创建连接,操作结束后关闭,这样也可以达到功能,只是损耗性能比较严重,无论是对PLC还是本机,通讯的效率也不是很理想,因为每次操作都是重新连接和关闭,这里的PLC实际上可以替换成数据库,Redis,其他任何的数据通信。
什么时候不能连接池
并不是所有的情况都可以使用连接池的,有个巨大的限制,如果服务器不支持多连接就很麻烦,比如说三菱PLC的服务器的端口,当然,一般的数据库,Redis,特殊的服务器都是支持。当然,有些特殊的服务器,支持的连接数是有上限的,没事,本组件也可以配置上限的连接数。
特性支持
本功能类的设计之初,就是兼顾灵活性,为了支持其他所有的不同类型的数据通信,采用接口+泛型来实现,先构建一个通信封装类,再进行创建一个连接池管理器,再调用使用。
- 支持配置最大的连接数
- 支持设置连接过期时间
- 支持任意的其他类型的连接对象变成连接池
实战示例
此处举例访问西门子的PLC,所以第一步是创建一个连接的封装类,除了实现接口外,还需要定义真实的连接对象。
public class SiemensConnector : HslCommunication.Algorithms.ConnectPool.IConnector { #region 构造方法 public SiemensConnector( string ipAddress ) { siemens = new HslCommunication.Profinet.Siemens.SiemensS7Net( HslCommunication.Profinet.Siemens.SiemensPLCS.S1200, ipAddress ); } #endregion #region IConnector 实现 /// <summary> /// 指示当前的连接是否在使用用 /// </summary> public bool IsConnectUsing { get; set; } /// <summary> /// 唯一的GUID码 /// </summary> public string GuidToken { get; set; } /// <summary> /// 最新一次使用的时间 /// </summary> public DateTime LastUseTime { get; set; } /// <summary> /// 打开连接 /// </summary> public void Open( ) { // 设置常连接。如果是Redis,可以连接服务器,数据库也是一样 siemens.ConnectServer( ); } /// <summary> /// 关闭并释放 /// </summary> public void Close( ) { // 关闭连接 siemens.ConnectClose( ); } #endregion #region Public Member /// <summary> /// 获取当前的连接对象,方便进行数据交互 /// </summary> /// <returns></returns> public HslCommunication.Profinet.Siemens.SiemensS7Net GetSiemens( ) { return siemens; } #endregion #region Private Member private HslCommunication.Profinet.Siemens.SiemensS7Net siemens; // 连接对象 #endregion }
定义好之后,就可以创建真正的连接池对象了
private HslCommunication.Algorithms.ConnectPool.ConnectPool<SiemensConnector> siemensConnect = null; // 西门子对象的连接池
然后初始化变量
siemensConnect = new HslCommunication.Algorithms.ConnectPool.ConnectPool<SiemensConnector>( ( ) => { return new SiemensConnector( "192.168.1.195" ); } ); siemensConnect.MaxConnector = 10; // 同时存在的最大连接数 siemensConnect.ConectionExpireTime = 30; // 连接多久不用就自动回收释放,单位秒
初始化的时候,有个地方需要注意,连接池需要知道一个信息,如何去创建一个新的连接对象,在这里可能创建默认的SiemesConnector就可以类,但是连接池的管理对象很有可能也是个接口,这时候就需要手动指示如何实例化一个新的对象。这种情况我在使用dapper的ORM的时候,支持mysql和sqlserver两种数据的时候就碰到过。
调用连接对象类,以下的代码可以出现在任何的后台线程:
// 这里的代码在单线程程序情况下,没有什么效果,但是在多线程情况下可以显著提升性能。 // 举例,此处要访问PLC的一个数据 SiemensConnector connector = siemensConnect.GetAvailableConnector( ); short m100 = connector.GetSiemens( ).ReadInt16( "M100" ).Content; // 使用完毕后归还连接 siemensConnect.ReturnConnector( connector );
使用完后务必归还连接对象,如果想要获取连接池里已经被激活的连接数
int online = siemensConnect.UsedConnector;
还有,在获取连接对象后,进行操作的时候,务必不要抛出异常,