• 5.3 Zinx-V0.5代码实现
    • A) Request字段修改
    • B) 集成拆包过程
    • C) 提供封包方法

    5.3 Zinx-V0.5代码实现

    现在我们需要把封包和拆包的功能集成到Zinx中,并且测试Zinx该功能是否生效。

    A) Request字段修改

    首先我们要将我们之前的Request中的[]byte类型的data字段改成Message类型.

    zinx/znet/request.go

    1. package znet
    2. import "zinx/ziface"
    3. type Request struct {
    4. conn ziface.IConnection //已经和客户端建立好的 链接
    5. msg ziface.IMessage //客户端请求的数据
    6. }
    7. //获取请求连接信息
    8. func(r *Request) GetConnection() ziface.IConnection {
    9. return r.conn
    10. }
    11. //获取请求消息的数据
    12. func(r *Request) GetData() []byte {
    13. return r.msg.GetData()
    14. }
    15. //获取请求的消息的ID
    16. func (r *Request) GetMsgID() uint32 {
    17. return r.msg.GetMsgId()
    18. }
    B) 集成拆包过程

    接下来我们需要在Connection的StartReader()方法中,修改之前的读取客户端的这段代码:

    1. func (c *Connection) StartReader() {
    2. //...
    3. for {
    4. //读取我们最大的数据到buf中
    5. buf := make([]byte, utils.GlobalObject.MaxPacketSize)
    6. _, err := c.Conn.Read(buf)
    7. if err != nil {
    8. fmt.Println("recv buf err ", err)
    9. c.ExitBuffChan <- true
    10. continue
    11. }
    12. //...
    13. }
    14. }

    改成如下:

    zinx/znet/connection.go

    StartReader()方法

    1. func (c *Connection) StartReader() {
    2. fmt.Println("Reader Goroutine is running")
    3. defer fmt.Println(c.RemoteAddr().String(), " conn reader exit!")
    4. defer c.Stop()
    5. for {
    6. // 创建拆包解包的对象
    7. dp := NewDataPack()
    8. //读取客户端的Msg head
    9. headData := make([]byte, dp.GetHeadLen())
    10. if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil {
    11. fmt.Println("read msg head error ", err)
    12. c.ExitBuffChan <- true
    13. continue
    14. }
    15. //拆包,得到msgid 和 datalen 放在msg中
    16. msg , err := dp.Unpack(headData)
    17. if err != nil {
    18. fmt.Println("unpack error ", err)
    19. c.ExitBuffChan <- true
    20. continue
    21. }
    22. //根据 dataLen 读取 data,放在msg.Data中
    23. var data []byte
    24. if msg.GetDataLen() > 0 {
    25. data = make([]byte, msg.GetDataLen())
    26. if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
    27. fmt.Println("read msg data error ", err)
    28. c.ExitBuffChan <- true
    29. continue
    30. }
    31. }
    32. msg.SetData(data)
    33. //得到当前客户端请求的Request数据
    34. req := Request{
    35. conn:c,
    36. msg:msg, //将之前的buf 改成 msg
    37. }
    38. //从路由Routers 中找到注册绑定Conn的对应Handle
    39. go func (request ziface.IRequest) {
    40. //执行注册的路由方法
    41. c.Router.PreHandle(request)
    42. c.Router.Handle(request)
    43. c.Router.PostHandle(request)
    44. }(&req)
    45. }
    46. }
    C) 提供封包方法

    现在我们已经将拆包的功能集成到Zinx中了,但是使用Zinx的时候,如果我们希望给用户返回一个TLV格式的数据,总不能每次都经过这么繁琐的过程,所以我们应该给Zinx提供一个封包的接口,供Zinx发包使用。

    zinx/ziface/iconnection.go

    新增SendMsg()方法

    1. package ziface
    2. import "net"
    3. //定义连接接口
    4. type IConnection interface {
    5. //启动连接,让当前连接开始工作
    6. Start()
    7. //停止连接,结束当前连接状态M
    8. Stop()
    9. //从当前连接获取原始的socket TCPConn
    10. GetTCPConnection() *net.TCPConn
    11. //获取当前连接ID
    12. GetConnID() uint32
    13. //获取远程客户端地址信息
    14. RemoteAddr() net.Addr
    15. //直接将Message数据发送数据给远程的TCP客户端
    16. SendMsg(msgId uint32, data []byte) error
    17. }

    zinx/znet/connection.go

    SendMsg()方法实现:

    1. //直接将Message数据发送数据给远程的TCP客户端
    2. func (c *Connection) SendMsg(msgId uint32, data []byte) error {
    3. if c.isClosed == true {
    4. return errors.New("Connection closed when send msg")
    5. }
    6. //将data封包,并且发送
    7. dp := NewDataPack()
    8. msg, err := dp.Pack(NewMsgPackage(msgId, data))
    9. if err != nil {
    10. fmt.Println("Pack error msg id = ", msgId)
    11. return errors.New("Pack error msg ")
    12. }
    13. //写回客户端
    14. if _, err := c.Conn.Write(msg); err != nil {
    15. fmt.Println("Write msg id ", msgId, " error ")
    16. c.ExitBuffChan <- true
    17. return errors.New("conn Write error")
    18. }
    19. return nil
    20. }