当我们在使用链接处理的时候,希望和链接绑定一些用户的数据,或者参数。那么我们现在可以把当前链接设定一些传递参数的接口或者方法。
10.1 给链接添加链接配置接口
zinx/ziface/iconnection.go
//定义连接接口type IConnection interface {//启动连接,让当前连接开始工作Start()//停止连接,结束当前连接状态MStop()//从当前连接获取原始的socket TCPConnGetTCPConnection() *net.TCPConn//获取当前连接IDGetConnID() 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属于哪个ServerTcpServer ziface.IServer//当前连接的socket TCP套接字Conn *net.TCPConn//当前连接的ID 也可以称作为SessionID,ID全局唯一ConnID uint32//当前连接的关闭状态isClosed bool//消息管理MsgId和对应处理方法的消息管理模块MsgHandler ziface.IMsgHandle//告知该链接已经退出/停止的channelExitBuffChan 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 mainimport ("fmt""zinx/ziface""zinx/znet")//ping test 自定义路由type PingRouter struct {znet.BaseRouter}//Ping Handlefunc (this *PingRouter) Handle(request ziface.IRequest) {fmt.Println("Call PingRouter Handle")//先读取客户端的数据,再回写ping...ping...pingfmt.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 Handlefunc (this *HelloZinxRouter) Handle(request ziface.IRequest) {fmt.Println("Call HelloZinxRouter Handle")//先读取客户端的数据,再回写ping...ping...pingfmt.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.goAdd api msgId = 0Add 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: 4096start 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= 0Call PingRouter Handlerecv from client : msgId= 0 , data= Zinx V0.8 Client0 Test MessageAdd ConnID= 0 request msgID= 0 to workerID= 0Call PingRouter Handlerecv from client : msgId= 0 , data= Zinx V0.8 Client0 Test MessageAdd ConnID= 0 request msgID= 0 to workerID= 0Call PingRouter Handlerecv from client : msgId= 0 , data= Zinx V0.8 Client0 Test Messageread msg head error read tcp4 127.0.0.1:7777->127.0.0.1:55208: read: connection reset by peerConn Stop()...ConnID = 0---> CallOnConnStop....Conn Property Name = AceldConn Property Home = https://www.jianshu.com/u/35261429b7f1DoConneciotnLost is Called ...connection Remove ConnID= 0 successfully: conn num = 0127.0.0.1:55208 [conn Reader exit!]127.0.0.1:55208 [conn Writer exit!]
客户端:
$ go run Client0.goClient 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
