🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 6.2 Zinx-V0.6代码实现 首先`iserver`的`AddRouter()`的接口要稍微改一下,增添MsgId参数 > zinx/ziface/iserver.go ```go package ziface //定义服务器接口 type IServer interface{ //启动服务器方法 Start() //停止服务器方法 Stop() //开启业务服务方法 Serve() //路由功能:给当前服务注册一个路由业务方法,供客户端链接处理使用 AddRouter(msgId uint32, router IRouter) } ``` 其次,`Server`类中 之前有一个`Router`成员 ,代表唯一的处理方法,现在应该替换成`MsgHandler`成员 > zinx/znet/server.go ```go type Server struct { //服务器的名称 Name string //tcp4 or other IPVersion string //服务绑定的IP地址 IP string //服务绑定的端口 Port int //当前Server的消息管理模块,用来绑定MsgId和对应的处理方法 msgHandler ziface.IMsgHandle } ``` 初始化Server自然也要更正,增加msgHandler初始化 ```go /* 创建一个服务器句柄 */ func NewServer () ziface.IServer { utils.GlobalObject.Reload() s:= &Server { Name :utils.GlobalObject.Name, IPVersion:"tcp4", IP:utils.GlobalObject.Host, Port:utils.GlobalObject.TcpPort, msgHandler: NewMsgHandle(), //msgHandler 初始化 } return s } ``` 然后当Server在处理conn请求业务的时候,创建conn的时候也需要把msgHandler作为参数传递给Connection对象 ```go //... dealConn := NewConntion(conn, cid, s.msgHandler) //... ``` 那么接下来就是Connection对象了。固然在Connection对象中应该有MsgHandler的成员,来查找消息对应的回调路由方法 > zinx/znet/connection.go ```go type Connection struct { //当前连接的socket TCP套接字 Conn *net.TCPConn //当前连接的ID 也可以称作为SessionID,ID全局唯一 ConnID uint32 //当前连接的关闭状态 isClosed bool //消息管理MsgId和对应处理方法的消息管理模块 MsgHandler ziface.IMsgHandle //告知该链接已经退出/停止的channel ExitBuffChan chan bool } //创建连接的方法 func NewConntion(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection{ c := &Connection{ Conn: conn, ConnID: connID, isClosed: false, MsgHandler: msgHandler, ExitBuffChan: make(chan bool, 1), } return c } ``` 最后,在conn已经拆包之后,需要调用路由业务的时候,我们只需要让conn调用MsgHandler中的`DoMsgHander()`方法就好了 > zinx/znet/connection.go ```go func (c *Connection) StartReader() { fmt.Println("[Reader Goroutine is running]") defer fmt.Println(c.RemoteAddr().String(), "[conn Reader exit!]") defer c.Stop() for { // 创建拆包解包的对象 dp := NewDataPack() //读取客户端的Msg head headData := make([]byte, dp.GetHeadLen()) if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil { fmt.Println("read msg head error ", err) break } //拆包,得到msgid 和 datalen 放在msg中 msg , err := dp.Unpack(headData) if err != nil { fmt.Println("unpack error ", err) break } //根据 dataLen 读取 data,放在msg.Data中 var data []byte if msg.GetDataLen() > 0 { data = make([]byte, msg.GetDataLen()) if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil { fmt.Println("read msg data error ", err) continue } } msg.SetData(data) //得到当前客户端请求的Request数据 req := Request{ conn:c, msg:msg, } //从绑定好的消息和对应的处理方法中执行对应的Handle方法 go c.MsgHandler.DoMsgHandler(&req) } } ``` 好了,大功告成,我们来测试一下Zinx的多路由设置功能吧。