Zinx-V0.9链接管理
我们要为Zinx框架增加链接个数的限定,如果超过一定量的客户端个数,Zinx为了保证后端的及时响应,而拒绝链接请求。
1.在抽象层添加链接管理模块的一些方法
type IConnManager interface {
//添加链接
Add(conn IConnection)
//删除链接
Remove(connID uint32)
//根据链接ID得到链接
Get(connID uint32) (IConnection, error)
//得到目前服务器的链接总个数
Len() int
//清空全部链接的方法
ClearConn()
}
2.在实现层实现这些方法
type ConnManager struct {
connections map[uint32] ziface.IConnection //管理的全部的链接
connLock sync.RWMutex
}
func NewConnManager() ziface.IConnManager {
return &ConnManager{
connections:make(map[uint32] ziface.IConnection),
}
}
//添加链接
func (connMgr *ConnManager) Add(conn ziface.IConnection) {
//加锁
connMgr.connLock.Lock()
defer connMgr.connLock.Unlock()
connMgr.connections[conn.GetConnID()] = conn
fmt.Println("Add connid = ", conn.GetConnID(), "to manager succ!!")
}
//删除链接
func (connMgr *ConnManager) Remove(connID uint32) {
//加锁
connMgr.connLock.Lock()
defer connMgr.connLock.Unlock()
delete(connMgr.connections, connID)
fmt.Println("Remove connid = ", connID, " from manager succ!!")
}
//根据链接ID得到链接
func (connMgr *ConnManager) Get(connID uint32) (ziface.IConnection, error) {
//加读锁
connMgr.connLock.RLock()
defer connMgr.connLock.RUnlock()
if conn, ok := connMgr.connections[connID]; ok {
//找到了
return conn, nil
} else {
//没找到
return nil, errors.New("connection not FOUND!")
}
}
//得到目前服务器的链接总个数
func (connMgr *ConnManager) Len() int {
return len(connMgr.connections)
}
//清空全部链接的方法
func (connMgr *ConnManager) ClearConn() {
//加锁
connMgr.connLock.Lock()
defer connMgr.connLock.Unlock()
//遍历删除
for connID, conn := range connMgr.connections {
//将全部的conn 关闭
conn.Stop()
//删除链接
delete(connMgr.connections, connID)
}
fmt.Println("Clear All Conections succ! conn num = ", connMgr.Len())
}
3.把链接管理模块集成到zinx
3.1.在Server中添加IConnManager属性
type Server struct {
......
//链接管理模块
connMgr ziface.IConnManager
}
3.2.在Server初始化时把ConnManager也初始化
func NewServer(name string) ziface.IServer{
s := &Server{
Name:config.GlobalObject.Name,
IPVersion:"tcp4",
IP:config.GlobalObject.Host,
Port:config.GlobalObject.Port,
MsgHandler:NewMsgHandler(),
connMgr:NewConnManager(),
}
return s
}
3.3.把每个IConnection添加到ConnManger中
3.3.1.在Connection中添加IServer属性(表示该Connection属于哪个Server)
type Connection struct {
//当前链接是属于哪个server创建
server ziface.IServer
......
}
3.3.2.在Iserver中添加GetConnMgr方法
type IServer interface {
//启动服务器
Start()
//停止服务器
Stop()
//运行服务器
Serve()
//提供一个得到链接管理模块的方法
GetConnMgr() IConnManager
}
对应在Server中实现这个方法
func (s *Server) GetConnMgr() ziface.IConnManager {
return s.connMgr
}
3.3.3.在IConnection初始化的时候将Server也初始化,并在初始化结束时将该IConnection添加到ConnManager
func NewConnection(server ziface.IServer, conn *net.TCPConn, connID uint32, handler ziface.IMsgHandler) ziface.IConnection {
c := &Connection{
server:server,
Conn:conn,
ConnID:connID,
//handleAPI:callback_api,
MsgHandler:handler,
isClosed:false,
msgChan: make(chan []byte), //初始化Reader Writer通信的Channel
writerExitChan:make(chan bool),
}
//当已经成功创建一个链接的时候,添加到链接管理器中
c.server.GetConnMgr().Add(c)
return c
}
这时Server中初始化IConnection时应该把Iserver也添加进去
dealConn := NewConnection(s, conn, cid, s.MsgHandler)
3.4.在建立连接时进行判断,如果超过用户定义的最大连接数量,就不再建立连接
......
//判断当前server链接数量是否已经最大值
if s.connMgr.Len() >= int(config.GlobalObject.MaxConn) {
//当前链接已经满了
fmt.Println("---> Too many Connection MAxConn = ", config.GlobalObject.MaxConn)
conn.Close()
continue
}
......
3.5.在连接关闭的时候将对应IConnection从ConnManager中删除
func (c *Connection) Stop() {
......
//关闭原生套接字
_ = c.Conn.Close()
//将当前链接从链接管理模块删除
c.server.GetConnMgr().Remove(c.ConnID)
......
}
4.注册链接启动/停止自定义Hook方法功能
有的时候,在创建链接的时候,希望在创建链接之后、和断开链接之前,执行一些用户自定义的业务。那么我们就需要给Zinx增添两个链接创建后和断开前时机的回调函数,一般也称作Hook(钩子)函数。
4.1.在IServer中加入对应方法
type IServer interface{
......
//设置该Server的连接创建时Hook函数
AddOnConnStart(func (conn IConnection))
//设置该Server的连接断开时的Hook函数
AddOnConnStop(func (conn IConnection))
//调用连接OnConnStart Hook函数
CallOnConnStart(conn IConnection)
//调用连接OnConnStop Hook函数
CallOnConnStop(conn IConnection)
}
4.2.在Server中实现对应方法
type Server struct {
......
//在Server的连接创建时Hook函数
OnConnStart func(conn ziface.IConnection)
//在Server的连接断开时的Hook函数
OnConnStop func(conn ziface.IConnection)
}
//注册 创建链接之后 调用的 Hook函数 的方法
func (s *Server) AddOnConnStart(hookFunc func (ziface.IConnection)) {
s.OnConnStart = hookFunc
}
//注册 销毁链接之前调用的Hook函数 的方法
func (s *Server) AddOnConnStop(hookFunc func (ziface.IConnection)) {
s.OnConnStop = hookFunc
}
//调用 创建链接之后的HOOK函数的方法
func (s *Server) CallOnConnStart(conn ziface.IConnection) {
if s.OnConnStart != nil {
fmt.Println("---> CallOnConnStart....")
s.OnConnStart(conn)
}
}
//调用 销毁链接之前调用的HOOk函数的方法
func (s *Server) CallOnConnStop(conn ziface.IConnection) {
if s.OnConnStop != nil {
fmt.Println("---> CallOnConnStop....")
s.OnConnStop(conn)
}
}
4.3.在创建连接之后调用CallOnConnStart
func (c *Connection) Start() {
fmt.Println("Conn Start() ... id = ", c.ConnID)
//先进行读业务
go c.StartReader()
//进行写业务
go c.StartWriter()
//调用创建链接之后 用户自定义的Hook业务
c.server.CallOnConnStart(c)
}
4.4.在断开连接之前调用CallOnConnStop
func (c *Connection) Stop() {
fmt.Println("c. Stop() ... ConnId = ", c.ConnID)
//调用销毁链接之前用户自定义的Hook函数
c.server.CallOnConnStop(c)
......