本文將使用一個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;
還有,在獲取連接對象后,進行操作的時候,務必不要拋出異常,
