美文网首页码农的世界Golang
【Zinx第十章-连接属性设置】Golang轻量级并发服务器框架

【Zinx第十章-连接属性设置】Golang轻量级并发服务器框架

作者: 刘丹冰Aceld | 来源:发表于2019-02-21 09:36 被阅读114次

    【Zinx教程目录】
    Zinx源代码: https://github.com/aceld/zinx
    Zinx第一章-引言
    Zinx第二章-初识Zinx框架
    Zinx第三章-基础路由模块
    Zinx第四章-全局配置
    Zinx第五章-消息封装
    Zinx第六章-多路由模式
    Zinx第七章-读写分离模型
    Zinx第八章-消息队列及多任务
    Zinx第九章-链接管理
    Zinx第十章-连接属性设置
    [连载中...]


    【Zinx应用案例-MMO多人在线游戏】
    (1)案例介绍
    (2)AOI兴趣点算法
    (3)数据传输协议protocol buffer
    (4)Proto3协议定义
    (5)构建项目及用户上线
    (6)世界聊天
    (7)上线位置信息同步
    [连载中...]


    ​ 当我们在使用链接处理的时候,希望和链接绑定一些用户的数据,或者参数。那么我们现在可以把当前链接设定一些传递参数的接口或者方法。

    10.1 给链接添加链接配置接口

    zinx/ziface/iconnection.go

    //定义连接接口
    type IConnection interface {
        //启动连接,让当前连接开始工作
        Start()
        //停止连接,结束当前连接状态M
        Stop()
    
        //从当前连接获取原始的socket TCPConn
        GetTCPConnection() *net.TCPConn
        //获取当前连接ID
        GetConnID() uint32
        //获取远程客户端地址信息
        RemoteAddr() net.Addr
    
        //直接将Message数据发送数据给远程的TCP客户端(无缓冲)
        SendMsg(msgId uint32, data []byte) error
        //直接将Message数据发送给远程的TCP客户端(有缓冲)
        SendBuffMsg(msgId uint32, data []byte) error
    
        //设置链接属性
        SetProperty(key string, value interface{})
        //获取链接属性
        GetProperty(key string)(interface{}, error)
        //移除链接属性
        RemoveProperty(key string)
    }
    

    ​ 这里增添了3个方法SetProperty(),GetProperty(),RemoveProperty().那么property是什么类型的呢,我么接下来看看Connection的定义。

    10.2 链接属性方法实现

    zinx/znet/connction.go

    type Connection struct {
        //当前Conn属于哪个Server
        TcpServer ziface.IServer
        //当前连接的socket TCP套接字
        Conn *net.TCPConn
        //当前连接的ID 也可以称作为SessionID,ID全局唯一
        ConnID uint32
        //当前连接的关闭状态
        isClosed bool
        //消息管理MsgId和对应处理方法的消息管理模块
        MsgHandler ziface.IMsgHandle
        //告知该链接已经退出/停止的channel
        ExitBuffChan chan bool
        //无缓冲管道,用于读、写两个goroutine之间的消息通信
        msgChan chan []byte
        //有关冲管道,用于读、写两个goroutine之间的消息通信
        msgBuffChan chan []byte
    
        // ================================
        //链接属性
        property     map[string]interface{}
        //保护链接属性修改的锁
        propertyLock sync.RWMutex
        // ================================
    }
    
    //创建连接的方法
    func NewConntion(server ziface.IServer, conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {
        //初始化Conn属性
        c := &Connection{
            TcpServer:    server,
            Conn:         conn,
            ConnID:       connID,
            isClosed:     false,
            MsgHandler:   msgHandler,
            ExitBuffChan: make(chan bool, 1),
            msgChan:      make(chan []byte),
            msgBuffChan:  make(chan []byte, utils.GlobalObject.MaxMsgChanLen),
            property:     make(map[string]interface{}), //对链接属性map初始化
        }
    
        //将新创建的Conn添加到链接管理中
        c.TcpServer.GetConnMgr().Add(c)
        return c
    }
    
    // ... 
    
    //设置链接属性
    func (c *Connection) SetProperty(key string, value interface{}) {
        c.propertyLock.Lock()
        defer c.propertyLock.Unlock()
    
        c.property[key] = value
    }
    
    //获取链接属性
    func (c *Connection) GetProperty(key string) (interface{}, error) {
        c.propertyLock.RLock()
        defer c.propertyLock.RUnlock()
    
        if value, ok := c.property[key]; ok  {
            return value, nil
        } else {
            return nil, errors.New("no property found")
        }
    }
    
    //移除链接属性
    func (c *Connection) RemoveProperty(key string) {
        c.propertyLock.Lock()
        defer c.propertyLock.Unlock()
    
        delete(c.property, key)
    }
    

    10.3 链接属性Zinx-V0.10单元测试

    ​ 那么,接下来,我们简单测试一下链接属性的设置与提取是否可用。

    Server.go

    package main
    
    import (
        "fmt"
        "zinx/ziface"
        "zinx/znet"
    )
    
    //ping test 自定义路由
    type PingRouter struct {
        znet.BaseRouter
    }
    
    //Ping Handle
    func (this *PingRouter) Handle(request ziface.IRequest) {
        fmt.Println("Call PingRouter Handle")
        //先读取客户端的数据,再回写ping...ping...ping
        fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
    
        err := request.GetConnection().SendBuffMsg(0, []byte("ping...ping...ping"))
        if err != nil {
            fmt.Println(err)
        }
    }
    
    type HelloZinxRouter struct {
        znet.BaseRouter
    }
    
    //HelloZinxRouter Handle
    func (this *HelloZinxRouter) Handle(request ziface.IRequest) {
        fmt.Println("Call HelloZinxRouter Handle")
        //先读取客户端的数据,再回写ping...ping...ping
        fmt.Println("recv from client : msgId=", request.GetMsgID(), ", data=", string(request.GetData()))
    
        err := request.GetConnection().SendBuffMsg(1, []byte("Hello Zinx Router V0.10"))
        if err != nil {
            fmt.Println(err)
        }
    }
    
    //创建连接的时候执行
    func DoConnectionBegin(conn ziface.IConnection) {
        fmt.Println("DoConnecionBegin is Called ... ")
    
        //=============设置两个链接属性,在连接创建之后===========
        fmt.Println("Set conn Name, Home done!")
        conn.SetProperty("Name", "Aceld")
        conn.SetProperty("Home", "https://www.jianshu.com/u/35261429b7f1")
        //===================================================
        
        err := conn.SendMsg(2, []byte("DoConnection BEGIN..."))
        if err != nil {
            fmt.Println(err)
        }
    }
    
    //连接断开的时候执行
    func DoConnectionLost(conn ziface.IConnection) {
        //============在连接销毁之前,查询conn的Name,Home属性=====
        if name, err:= conn.GetProperty("Name"); err == nil {
            fmt.Println("Conn Property Name = ", name)
        }
    
        if home, err := conn.GetProperty("Home"); err == nil {
            fmt.Println("Conn Property Home = ", home)
        }
        //===================================================
    
        fmt.Println("DoConneciotnLost is Called ... ")
    }
    
    func main() {
        //创建一个server句柄
        s := znet.NewServer()
    
        //注册链接hook回调函数
        s.SetOnConnStart(DoConnectionBegin)
        s.SetOnConnStop(DoConnectionLost)
    
        //配置路由
        s.AddRouter(0, &PingRouter{})
        s.AddRouter(1, &HelloZinxRouter{})
    
        //开启服务
        s.Serve()
    }
    
    

    这里主要看DoConnectionBegin()DoConnectionLost()两个函数的实现, 利用在两个Hook函数中,设置链接属性和提取链接属性。链接创建之后给当前链接绑定两个属性"Name","Home", 那么我们在随时可以通过conn.GetProperty()方法得到链接已经设置的属性。

    $go run Server.go
    
    $go run Client0.go
    

    服务端:

    $ go run Server.go 
    Add api msgId =  0
    Add api msgId =  1
    [START] Server name: zinx v-0.10 demoApp,listenner at IP: 127.0.0.1, Port 7777 is starting
    [Zinx] Version: V0.4, MaxConn: 3, MaxPacketSize: 4096
    start Zinx server   zinx v-0.10 demoApp  succ, now listenning...
    Worker ID =  9  is started.
    Worker ID =  5  is started.
    Worker ID =  6  is started.
    Worker ID =  7  is started.
    Worker ID =  8  is started.
    Worker ID =  1  is started.
    Worker ID =  0  is started.
    Worker ID =  2  is started.
    Worker ID =  3  is started.
    Worker ID =  4  is started.
    connection add to ConnManager successfully: conn num =  1
    ---> CallOnConnStart....
    DoConnecionBegin is Called ... 
    Set conn Name, Home done!
    [Writer Goroutine is running]
    [Reader Goroutine is running]
    Add ConnID= 0  request msgID= 0 to workerID= 0
    Call PingRouter Handle
    recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    Add ConnID= 0  request msgID= 0 to workerID= 0
    Call PingRouter Handle
    recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    Add ConnID= 0  request msgID= 0 to workerID= 0
    Call PingRouter Handle
    recv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Message
    read msg head error  read tcp4 127.0.0.1:7777->127.0.0.1:55208: read: connection reset by peer
    Conn Stop()...ConnID =  0
    ---> CallOnConnStop....
    Conn Property Name =  Aceld
    Conn Property Home =  https://www.jianshu.com/u/35261429b7f1
    DoConneciotnLost is Called ... 
    connection Remove ConnID= 0  successfully: conn num =  0
    127.0.0.1:55208 [conn Reader exit!]
    127.0.0.1:55208 [conn Writer exit!]
    
    

    客户端:

    $ go run Client0.go 
    Client Test ... start
    ==> Recv Msg: ID= 2 , len= 21 , data= DoConnection BEGIN...
    ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    ==> Recv Msg: ID= 0 , len= 18 , data= ping...ping...ping
    ^Csignal: interrupt
    
    

    当我们终止客户端链接,那么服务端在断开链接之前,已经读取到了conn的两个属性Name和Home。


    关于作者:

    作者:Aceld(刘丹冰)
    简书号:IT无崖子

    mail: danbing.at@gmail.com
    github: https://github.com/aceld
    原创书籍gitbook: http://legacy.gitbook.com/@aceld

    原创声明:未经作者允许请勿转载, 如果转载请注明出处

    相关文章

      网友评论

        本文标题:【Zinx第十章-连接属性设置】Golang轻量级并发服务器框架

        本文链接:https://www.haomeiwen.com/subject/wublyqtx.html