• 6.2 Zinx-V0.6代码实现

    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的多路由设置功能吧。