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

Zinx源代码

github
https://github.com/aceld/zinx
gitee码云
https://gitee.com/Aceld/zinx


在线开发教程

【B站】
zinx视频教程-Golang轻量级TCP服务器框架-适合自学者

【YouTube】
zinx开发YouTube中国版

微信端文档

【Zinx第十章-连接属性设置】Golang轻量级并发服务器框架_第1张图片
技术资源分享.jpg

【Zinx教程目录】
完整教程电子版(在线高清)-下载
Zinx框架视频教程(框架篇)(完整版下载)链接在下面正文
Zinx框架视频教程(应用篇)(完整版下载)链接在下面正文
Zinx开发API文档
Zinx第一章-引言
Zinx第二章-初识Zinx框架
Zinx第三章-基础路由模块
Zinx第四章-全局配置
Zinx第五章-消息封装
Zinx第六章-多路由模式
Zinx第七章-读写分离模型
Zinx第八章-消息队列及多任务
Zinx第九章-链接管理
Zinx第十章-连接属性设置


【Zinx应用案例-MMO多人在线游戏】
(1)案例介绍
(2)AOI兴趣点算法
(3)数据传输协议protocol buffer
(4)Proto3协议定义
(5)构建项目及用户上线
(6)世界聊天
(7)上线位置信息同步
(8)移动位置与AOI广播
(9)玩家下线
(10)模拟客户端AI模块


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

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: [email protected]
github: https://github.com/aceld
原创书籍gitbook: http://legacy.gitbook.com/@aceld

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

你可能感兴趣的:(【Zinx第十章-连接属性设置】Golang轻量级并发服务器框架)