本文將使用一個Github開源的組件庫技術來實現鏈接池的操做,應用於一些狀況下的頻繁的網絡鏈接操做。html
github地址:https://github.com/dathlin/HslCommunication 若是喜歡能夠star或是fork,還能夠打賞支持,打賞請認準源代碼項目。java
本項目目前支持C#語言和java語言,C#語言的功能比較齊全,java版本的庫還在開發及完善中。mysql
nuget地址:https://www.nuget.org/packages/HslCommunication/
git
github地址:https://github.com/dathlin/HslCommunication
若是喜歡能夠star或是fork,還能夠打賞支持。github
組件的完整信息和API介紹參照:http://www.cnblogs.com/dathlin/p/7703805.html 組件的使用限制,更新日誌,都在該頁面裏面。sql
首先須要解決這個問題,咱們爲何須要鏈接池,終極目的是是爲了高效的數據訪問,但並非全部狀況都須要進行鏈接池搭建的,舉幾個🌰吧數據庫
案例一:你有個後臺線程每隔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;
還有,在獲取鏈接對象後,進行操做的時候,務必不要拋出異常,