🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
#### 5.3 Zinx-V0.5代码实现 现在我们需要把封包和拆包的功能集成到Zinx中,并且测试Zinx该功能是否生效。 ##### A\) Request字段修改 首先我们要将我们之前的Request中的`[]byte`类型的data字段改成Message类型. > zinx/znet/request.go ```go package znet import "zinx/ziface" type Request struct { conn ziface.IConnection //已经和客户端建立好的 链接 msg ziface.IMessage //客户端请求的数据 } //获取请求连接信息 func(r *Request) GetConnection() ziface.IConnection { return r.conn } //获取请求消息的数据 func(r *Request) GetData() []byte { return r.msg.GetData() } //获取请求的消息的ID func (r *Request) GetMsgID() uint32 { return r.msg.GetMsgId() } ``` ##### B\) 集成拆包过程 接下来我们需要在Connection的`StartReader()`方法中,修改之前的读取客户端的这段代码: ```go func (c *Connection) StartReader() { //... for { //读取我们最大的数据到buf中 buf := make([]byte, utils.GlobalObject.MaxPacketSize) _, err := c.Conn.Read(buf) if err != nil { fmt.Println("recv buf err ", err) c.ExitBuffChan <- true continue } //... } } ``` 改成如下: > zinx/znet/connection.go StartReader\(\)方法 ```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) c.ExitBuffChan <- true continue } //拆包,得到msgid 和 datalen 放在msg中 msg , err := dp.Unpack(headData) if err != nil { fmt.Println("unpack error ", err) c.ExitBuffChan <- true continue } //根据 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) c.ExitBuffChan <- true continue } } msg.SetData(data) //得到当前客户端请求的Request数据 req := Request{ conn:c, msg:msg, //将之前的buf 改成 msg } //从路由Routers 中找到注册绑定Conn的对应Handle go func (request ziface.IRequest) { //执行注册的路由方法 c.Router.PreHandle(request) c.Router.Handle(request) c.Router.PostHandle(request) }(&req) } } ``` ##### C\) 提供封包方法 现在我们已经将拆包的功能集成到Zinx中了,但是使用Zinx的时候,如果我们希望给用户返回一个TLV格式的数据,总不能每次都经过这么繁琐的过程,所以我们应该给Zinx提供一个封包的接口,供Zinx发包使用。 > zinx/ziface/iconnection.go 新增`SendMsg()`方法 ```go package ziface import "net" //定义连接接口 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 } ``` > zinx/znet/connection.go `SendMsg()`方法实现: ```go //直接将Message数据发送数据给远程的TCP客户端 func (c *Connection) SendMsg(msgId uint32, data []byte) error { if c.isClosed == true { return errors.New("Connection closed when send msg") } //将data封包,并且发送 dp := NewDataPack() msg, err := dp.Pack(NewMsgPackage(msgId, data)) if err != nil { fmt.Println("Pack error msg id = ", msgId) return errors.New("Pack error msg ") } //写回客户端 if _, err := c.Conn.Write(msg); err != nil { fmt.Println("Write msg id ", msgId, " error ") c.ExitBuffChan <- true return errors.New("conn Write error") } return nil } ```