现在我们需要把封包和拆包的功能集成到Zinx中,并且测试Zinx该功能是否生效。
A) Request字段修改
首先我们要将我们之前的Request中的[]byte类型的data字段改成Message类型.
zinx/znet/request.go
package znetimport "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()}//获取请求的消息的IDfunc (r *Request) GetMsgID() uint32 {return r.msg.GetMsgId()}
B) 集成拆包过程
接下来我们需要在Connection的StartReader()方法中,修改之前的读取客户端的这段代码:
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 <- truecontinue}//...}}
改成如下:
zinx/znet/connection.go
StartReader()方法
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 headheadData := make([]byte, dp.GetHeadLen())if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {fmt.Println("read msg head error ", err)c.ExitBuffChan <- truecontinue}//拆包,得到msgid 和 datalen 放在msg中msg , err := dp.Unpack(headData)if err != nil {fmt.Println("unpack error ", err)c.ExitBuffChan <- truecontinue}//根据 dataLen 读取 data,放在msg.Data中var data []byteif 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 <- truecontinue}}msg.SetData(data)//得到当前客户端请求的Request数据req := Request{conn:c,msg:msg, //将之前的buf 改成 msg}//从路由Routers 中找到注册绑定Conn的对应Handlego 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()方法
package zifaceimport "net"//定义连接接口type IConnection interface {//启动连接,让当前连接开始工作Start()//停止连接,结束当前连接状态MStop()//从当前连接获取原始的socket TCPConnGetTCPConnection() *net.TCPConn//获取当前连接IDGetConnID() uint32//获取远程客户端地址信息RemoteAddr() net.Addr//直接将Message数据发送数据给远程的TCP客户端SendMsg(msgId uint32, data []byte) error}
zinx/znet/connection.go
SendMsg()方法实现:
//直接将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 <- truereturn errors.New("conn Write error")}return nil}
