6.2 Zinx-V0.6代码实现

首先iserverAddRouter()的接口要稍微改一下,增添MsgId参数

zinx/ziface/iserver.go

  1. package ziface
  2. //定义服务器接口
  3. type IServer interface{
  4. //启动服务器方法
  5. Start()
  6. //停止服务器方法
  7. Stop()
  8. //开启业务服务方法
  9. Serve()
  10. //路由功能:给当前服务注册一个路由业务方法,供客户端链接处理使用
  11. AddRouter(msgId uint32, router IRouter)
  12. }

其次,Server类中 之前有一个Router成员 ,代表唯一的处理方法,现在应该替换成MsgHandler成员

zinx/znet/server.go

  1. type Server struct {
  2. //服务器的名称
  3. Name string
  4. //tcp4 or other
  5. IPVersion string
  6. //服务绑定的IP地址
  7. IP string
  8. //服务绑定的端口
  9. Port int
  10. //当前Server的消息管理模块,用来绑定MsgId和对应的处理方法
  11. msgHandler ziface.IMsgHandle
  12. }

初始化Server自然也要更正,增加msgHandler初始化

  1. /*
  2. 创建一个服务器句柄
  3. */
  4. func NewServer () ziface.IServer {
  5. utils.GlobalObject.Reload()
  6. s:= &Server {
  7. Name :utils.GlobalObject.Name,
  8. IPVersion:"tcp4",
  9. IP:utils.GlobalObject.Host,
  10. Port:utils.GlobalObject.TcpPort,
  11. msgHandler: NewMsgHandle(), //msgHandler 初始化
  12. }
  13. return s
  14. }

然后当Server在处理conn请求业务的时候,创建conn的时候也需要把msgHandler作为参数传递给Connection对象

  1. //...
  2. dealConn := NewConntion(conn, cid, s.msgHandler)
  3. //...

那么接下来就是Connection对象了。固然在Connection对象中应该有MsgHandler的成员,来查找消息对应的回调路由方法

zinx/znet/connection.go

  1. type Connection struct {
  2. //当前连接的socket TCP套接字
  3. Conn *net.TCPConn
  4. //当前连接的ID 也可以称作为SessionID,ID全局唯一
  5. ConnID uint32
  6. //当前连接的关闭状态
  7. isClosed bool
  8. //消息管理MsgId和对应处理方法的消息管理模块
  9. MsgHandler ziface.IMsgHandle
  10. //告知该链接已经退出/停止的channel
  11. ExitBuffChan chan bool
  12. }
  13. //创建连接的方法
  14. func NewConntion(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection{
  15. c := &Connection{
  16. Conn: conn,
  17. ConnID: connID,
  18. isClosed: false,
  19. MsgHandler: msgHandler,
  20. ExitBuffChan: make(chan bool, 1),
  21. }
  22. return c
  23. }

最后,在conn已经拆包之后,需要调用路由业务的时候,我们只需要让conn调用MsgHandler中的DoMsgHander()方法就好了

zinx/znet/connection.go

  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. break
  13. }
  14. //拆包,得到msgid 和 datalen 放在msg中
  15. msg , err := dp.Unpack(headData)
  16. if err != nil {
  17. fmt.Println("unpack error ", err)
  18. break
  19. }
  20. //根据 dataLen 读取 data,放在msg.Data中
  21. var data []byte
  22. if msg.GetDataLen() > 0 {
  23. data = make([]byte, msg.GetDataLen())
  24. if _, err := io.ReadFull(c.GetTCPConnection(), data); err != nil {
  25. fmt.Println("read msg data error ", err)
  26. continue
  27. }
  28. }
  29. msg.SetData(data)
  30. //得到当前客户端请求的Request数据
  31. req := Request{
  32. conn:c,
  33. msg:msg,
  34. }
  35. //从绑定好的消息和对应的处理方法中执行对应的Handle方法
  36. go c.MsgHandler.DoMsgHandler(&req)
  37. }
  38. }

好了,大功告成,我们来测试一下Zinx的多路由设置功能吧。