Zinx - V0.6 多路由实现
- 之前在已经给Zinx配置了路由模式,但是之前的Zinx只能绑定一个路由的处理业务方法
- 显然这是无法满足基本的服务器需求,需要给Zinx添加多路由的方案
- 查看之前的Server定义,路由Router只有一个,当我们想要再添加一个路由时就会将旧的路由替换掉
实现思路
消息管理模块实现
imsgHandler.go
package ziface
//消息管理抽象层
type IMsgHandle interface {
// 调度/执行对应的Router消息处理方法
DoMsgHandler(request IRequest)
// 为消息添加具体的处理逻辑
AddRouter(msgID uint32, router IRouter)
}
msgHandler.go
package znet
import (
"fmt"
"strconv"
"zinx/ziface"
)
//消息处理模块的实现
type MsgHandle struct {
//存放每个MsgID 所对应的处理方法
Apis map[uint32]ziface.IRouter
}
//初始化/创建MsgHandle方法
func NewMsgHandle() *MsgHandle {
return &MsgHandle{
Apis: make(map[uint32]ziface.IRouter),
}
}
// 调度/执行对应的Router消息处理方法
func (mh *MsgHandle) DoMsgHandler(request ziface.IRequest) {
//1 从Request中找到msgID
handler, ok := mh.Apis[request.GetMsgID()]
if !ok {
fmt.Println("api msgID = ", request.GetMsgID(), " is NOT FOUND! Need Register!")
}
//2 根据MsgID 调度对应router业务即可
handler.PreHandle(request)
handler.Handle(request)
handler.PostHandle(request)
}
// 为消息添加具体的处理逻辑
func (mh *MsgHandle) AddRouter(msgID uint32, router ziface.IRouter) {
//1 判断 当前msg绑定的API处理方法是否已经存在
if _, ok := mh.Apis[msgID]; ok {
//id已经注册了
panic("repeat api , msgID = " + strconv.Itoa(int(msgID)))
}
//2 添加msg与API的绑定关系
mh.Apis[msgID] = router
fmt.Println("Add api MsgID = ", msgID, " succ!")
}
Zinx集成消息管理模块
- server.go
Server结构体将之前的Handle替换成MsgHandler
//iServer的接口实现,定义一个Server的服务器模块
type Server struct {
//服务器的名称
Name string
//服务器绑定的ip版本
IPVersion string
//服务器监听的IP
IP string
//服务器监听的端口
Port int
//当前server的消息管理模块, 用来绑定MsgID和对应的处理业务API关系
MsgHandler ziface.IMsgHandle
}
AddRouter方法修改成MsgHandler.AddRouter
//路由功能:给当前的服务注册一个路由方法,供客户端的链接处理使用
func (s *Server) AddRouter(msgID uint32, router ziface.IRouter) {
s.MsgHandler.AddRouter(msgID, router)
fmt.Println("Add Router Succ!!")
}
初始化Server模块方法修改
//初始化Server模块的方法
func NewServer(name string) ziface.IServer {
s := &Server{
Name: utils.GlobalObject.Name,
IPVersion: "tcp4",
IP: utils.GlobalObject.Host,
Port: utils.GlobalObject.TcpPort,
MsgHandler: NewMsgHandle(),
}
return s
}
Start中NewConnection调用的修改
//启动服务器
func (s *Server) Start() {
...
// 将处理新连接的业务方法 和 conn 进行绑定 得到我们的链接模块
dealConn := NewConnection(conn, cid, s.MsgHandler)
cid++
...
}
- iserver.go
修改对应的AddRouter定义
package ziface
//定义一个服务器接口
type IServer interface {
//启动服务器
Start()
//停止服务器
Stop()
//运行服务器
Serve()
//路由功能:给当前的服务注册一个路由方法,供客户端的链接处理使用
AddRouter(uint32, IRouter)
}
- connection.go
Connection结构体定义修改
type Connection struct {
...
//消息的管理MsgID 和对应的处理业务API关系
MsgHandler ziface.IMsgHandle
}
NewConnection方法修改
//初始化链接模块的方法
func NewConnection(conn *net.TCPConn, connID uint32, msgHandler ziface.IMsgHandle) *Connection {
c := &Connection{
Conn: conn,
ConnID: connID,
MsgHandler: msgHandler,
isClosed: false,
ExitChan: make(chan bool, 1),
}
return c
}
StartReader方法修改
//链接的读业务方法
func (c *Connection) StartReader() {
...
//从路由中,找到注册绑定的Conn对应的router调用
//根据绑定好的MsgID 找到对应处理api业务 执行
go c.MsgHandler.DoMsgHandler(&req)
}
}
Zinx框架开发
- Client0 发送ID为0的消息
package main
import (
"fmt"
"io"
"net"
"time"
"zinx/znet"
)
//模拟客户端
func main() {
fmt.Println("client0 start...")
time.Sleep(1 * time.Second)
//1 直接链接远程服务器,得到一个conn链接
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
fmt.Println("client start err, exit!")
return
}
for {
//发送封包的message消息 MsgID:0
dp := znet.NewDataPack()
binaryMsg, err := dp.Pack(znet.NewMsgPackage(0, []byte("Zinx client0 Test Message")))
if err != nil {
fmt.Println("Pack error:", err)
return
}
if _, err := conn.Write(binaryMsg); err != nil {
fmt.Println("write error", err)
return
}
//服务器就应该给我们回复一个message数据, MsgID:1 pingpingping
// 1 先读取流中的head部分 得到ID 和 dataLen
binaryHead := make([]byte, dp.GetHeadLen())
if _, err := io.ReadFull(conn, binaryHead); err != nil {
fmt.Println("read head error ", err)
break
}
// 将二进制的head拆包到msg 结构体中
msgHead, err := dp.Unpack(binaryHead)
if err != nil {
fmt.Println("client unpack msgHead error ", err)
break
}
if msgHead.GetMsgLen() > 0 {
// 2再根据DataLen进行第二次读取,将data读出来
msg := msgHead.(*znet.Message)
msg.Data = make([]byte, msg.GetMsgLen())
if _, err := io.ReadFull(conn, msg.Data); err != nil {
fmt.Println("read msg data error , ", err)
return
}
fmt.Println("---> Recv Server Msg : ID = ", msg.Id, ", len = ", msg.DataLen, ", data = ", string(msg.Data))
}
//cpu阻塞
time.Sleep(1 * time.Second)
}
}
- Client1 发送ID为1的消息
package main
import (
"fmt"
"io"
"net"
"time"
"zinx/znet"
)
//模拟客户端
func main() {
fmt.Println("client1 start...")
time.Sleep(1 * time.Second)
//1 直接链接远程服务器,得到一个conn链接
conn, err := net.Dial("tcp", "127.0.0.1:8999")
if err != nil {
fmt.Println("client start err, exit!")
return
}
for {
//发送封包的message消息 MsgID:0
dp := znet.NewDataPack()
binaryMsg, err := dp.Pack(znet.NewMsgPackage(1, []byte("Zinx client1 Test Message")))
if err != nil {
fmt.Println("Pack error:", err)
return
}
if _, err := conn.Write(binaryMsg); err != nil {
fmt.Println("write error", err)
return
}
//服务器就应该给我们回复一个message数据, MsgID:1 pingpingping
// 1 先读取流中的head部分 得到ID 和 dataLen
binaryHead := make([]byte, dp.GetHeadLen())
if _, err := io.ReadFull(conn, binaryHead); err != nil {
fmt.Println("read head error ", err)
break
}
// 将二进制的head拆包到msg 结构体中
msgHead, err := dp.Unpack(binaryHead)
if err != nil {
fmt.Println("client unpack msgHead error ", err)
break
}
if msgHead.GetMsgLen() > 0 {
// 2再根据DataLen进行第二次读取,将data读出来
msg := msgHead.(*znet.Message)
msg.Data = make([]byte, msg.GetMsgLen())
if _, err := io.ReadFull(conn, msg.Data); err != nil {
fmt.Println("read msg data error , ", err)
return
}
fmt.Println("---> Recv Server Msg : ID = ", msg.Id, ", len = ", msg.DataLen, ", data = ", string(msg.Data))
}
//cpu阻塞
time.Sleep(1 * time.Second)
}
}
- server.go 多Router:0 - PingRouter;1 - HelloZinxRouter
package main
import (
"fmt"
"zinx/ziface"
"zinx/znet"
)
//基于Zinx框架来开发的 服务器端应用程序
//ping test 自定义路由
type PingRouter struct {
znet.BaseRouter
}
//Test Handle
func (this *PingRouter) Handle(request ziface.IRequest) {
fmt.Println("Call PingRouter Handle...")
//先读取客户端的数据,再回写ping..ping...ping
fmt.Println("recv from client: msgID = ", request.GetMsgID(),
", data = ", string(request.GetData()))
err := request.GetConnection().SendMsg(200, []byte("ping...ping...ping"))
if err != nil {
fmt.Println(err)
}
}
//hello Zinx test 自定义路由
type HelloZinxRouter struct {
znet.BaseRouter
}
//Test Handle
func (this *HelloZinxRouter) Handle(request ziface.IRequest) {
fmt.Println("Call HelloZinxRouter Handle...")
//先读取客户端的数据,再回写ping..ping...ping
fmt.Println("recv from client: msgID = ", request.GetMsgID(),
", data = ", string(request.GetData()))
err := request.GetConnection().SendMsg(201, []byte("Hello Welcome to Zinx!!"))
if err != nil {
fmt.Println(err)
}
}
func main() {
//1 创建一个server句柄,使用Zinx的api
s := znet.NewServer("[zinx V0.6]")
//2 给当前zinx框架添加自定义的router
s.AddRouter(0, &PingRouter{})
s.AddRouter(1, &HelloZinxRouter{})
//3 启动server
s.Serve()
}