天天看点

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连接池管理器