天天看點

ESFramework介紹之(10)-- Tcp連接配接池

    凡是帶有“池”的,比如資料庫連接配接池、對象池、緩沖區池(後面可以看到IBuffPool)等等,都是為了避免資源的反複建立/銷毀所帶來的開銷。需要為哪些資源對象建立“池”了?這些資源對象通常符合下面幾個特性:

(1)在應用中需要反複的被建立/銷毀。

(2)建立/銷毀的開銷比較大

(3)應用中給定時刻,對該資源對象的數量要求比較大

(4)資源對象最好是無狀态的(Stateless),這樣友善直接複用

    如你所想,ESFramework推薦的方式是AS和FS直接通過低層的Tcp進行通信。為了避免Tcp連接配接不斷建立、銷毀所帶來的開銷,AS和FS通信前,可以建立Tcp連接配接池。本文就關注Tcp連接配接池的原理和實作。

    Tcp連接配接池中存放的是Tcp連接配接――即NetworkStream對象,當應用需要使用時,就從Tcp連接配接池中租借“Rent”一條連接配接,用完後再歸還“GiveBack”給連接配接池。

public class TcpStreamPool :ITcpStreamPool ,ITcpPool

    從上面的定義可以看到TcpStreamPool從兩個接口繼承:ITcpPool和ITcpStreamPool。先看看ITcpStreamPool的定義:

 1     /// <summary>

 2     /// ITCPStreamPool tcp連接配接池用于管理大量的TCP連接配接

 3     ///  作者:朱偉 [email protected]  

 4     /// sky 2005.02.24

 5     /// </summary>

 6     public interface ITcpStreamPool 

 7     {        

 8         int         ServerID {get ;set ;}

 9         int            StreamCount           {get ;set ;} //期望連接配接總數

10         int            ActiveConnectionCount {get ;} //實際可用的連接配接數        

11         IPEndPoint  FsIpe       {get ;set ;} //功能伺服器的IPE

12         int         ReconnectSpan{get ;set ;} // 分鐘     

13         bool        IsActive{get;}

14 

15         void ReConnect() ; //手動重連

16         void Initialize() ;        

17         void DisposeConnections() ; //釋放池中所有連接配接,可以通過ReConnect來重建立立連接配接        

18         void SetStreamDamaged(int streamHashCode) ;            

19 

20         NetworkStream RentTcpStream() ;    

21         void GiveBackTcpStream(int streamHashCode) ;//将tcp連接配接規還給連接配接池

22     }    

    AS和每個FS之間都有一個連接配接池,每個功能伺服器的區分是通過ServerID來的,是以連接配接池也有一個ServerID屬性标志了本連接配接池是與哪個FS相連的。ReconnectSpan屬性表明連接配接池要支援重連機制,即當連接配接池中的所有連接配接都斷開後(可能是FS掉線引起的),連接配接池應能定時重連FS,直至該池中的所有連接配接重建立立。

    如果應用從連接配接池Rent了一條連接配接,然後在使用的過程中該連接配接斷開了,則應用應該調用連接配接池的SetStreamDamaged方法通知連接配接池該連接配接已不可用。RentTcpStream方法和GiveBackTcpStream方法是我們最常用的租借/歸還連接配接的方法了。

    注意,很多方法的參數中有streamHashCode參數,它是NetworkStream對象的Hashcode,系統中的每個NetworkStream對象的HashCode是不同的,并且,它的HashCode在NetworkStream對象的整個生命期間不變,是以可以使用HashCode唯一标志每個連接配接。

    似乎,ITcpStreamPool接口已經反映了一個連接配接池的所有東西,是的。那麼ITcpPool接口又起什麼作用了?現看看ITcpPool的樣子:

 1 /// <summary>

 2     /// ITcpPool 用于将一個TCP連接配接池和一組TCP連接配接池統一起來。這樣消息分派器隻需使用ITcpPool接口即可。

 3     /// zhuweisky 

 4     /// </summary>

 5     public interface ITcpPool

 6     {

 7         RentStreamResult RentTcpStream(int poolTypeKey ,int serviceKey ,out NetworkStream stream ,out int serverID) ;//poolTypeKey表示某個城市,serviceKey表示某項服務

 8         void GiveBackTcpStream(int streamHashCode ,int serverID) ;//将tcp連接配接規還給連接配接池

 9         void SetStreamDamaged(int streamHashCode ,int serverID) ;//poolKey如果不易儲存,則此處簡單的傳-1即可    

10 

11         event CallBackCountChanged     ActiveConnectionCountChanged ;     

12         event CallBackPoolStateChanged PoolStateChanged ;        

13     }

15     public delegate void CallBackCountChanged(int serverID ,int activeConnCount) ;

16     public delegate void CallBackPoolStateChanged(int serverID ,bool disconnected) ;

17 

18     public enum RentStreamResult

19     {

20         Succeed ,Busy ,TheServiceNotExist

21     }

    你可能已經發現,ITcpPool中的所有元素在ITcpStreamPool接口中都可以找到對應物,隻是有些方法的參數變複雜了。這主要是因為ITcpStreamPool接口針對的是一個FS,而ITcpPool可能是針對一個FS也可能是一組FS。當ITcpPool背後是一組FS時,就需要參數ServerID來區分每一個FS。我們知道,AS和對應的每個FS之間都使用一個Tcp連接配接池通信:

    所有的這些連接配接池需要被管理起來,ESFramework中的ITcpPoolsManager(連接配接池管理器)元件實作了對多個Tcp連接配接池的管理。為了把連接配接池管理器和單個連接配接池統一起來,使它們有相同的外部接口,是以引入了ITcpPool接口。

    這樣做的好處是,在應用中直接使用ITcpPool接口就可以了,而不用關心這個接口背後是一個“單個連接配接池”(對應單個FS)還是由連接配接池管理器管理的“一組連接配接池”(對應多個FS)。而且ITcpPoolsManager為我們的應用進行了很多複雜的管理,比如動能伺服器的排程(實作FS的負載均衡)、連接配接池的動态添加/移除等。這些将在下文中介紹。

下一篇文章:ESFramework介紹之(11)-- Tcp連接配接池管理器