skeleton.RegisterChanRPC("NewAgent", rpcNewAgent)
其实在game模块的handler.go中,同样注册了如何处理网络消息:
func init() { // 向当前模块(game 模块)注册 消息处理函数 handler(&msg.Test{}, handleTest) handler(&msg.UserLogin{}, handleUserLogin) handler(&msg.UserRegister{}, handleUserRegister) } func handler(m interface{}, h interface{}) { skeleton.RegisterChanRPC(reflect.TypeOf(m), h) } func handleTest(args []interface{}) { // 收到的 Test 消息 m := args[0].(*msg.Test) // 消息的发送者 a := args[1].(gate.Agent) // 输出收到的消息的内容 log.Debug("hello %v", m.GetTest()) retBuf := &msg.Test{ Test: *proto.String("client"), } // 给发送者回应一个 Test 消息 a.WriteMsg(retBuf) }
也就是说,他们和内部模块通讯方式是一样的,也是用chanrpc。当然,我们还要做一些准备工作
一、流程简述
1.msg模块
// 使用 Protobuf 消息处理器 var Processor = protobuf.NewProcessor() func init() { id1 := Processor.Register(&Test{}) id2 := Processor.Register(&UserLogin{}) id3 := Processor.Register(&UserRegister{}) id4 := Processor.Register(&UserResult{}) id5 := Processor.Register(&UserST{}) }
指定Processor并注册
2.在gate的router.go中设置路由
func init() { // 这里指定消息 路由到 game 模块 msg.Processor.SetRouter(&msg.Test{}, game.ChanRPC) msg.Processor.SetRouter(&msg.UserLogin{}, game.ChanRPC) msg.Processor.SetRouter(&msg.UserRegister{}, game.ChanRPC) }
3.简述
&msg.Test{}
// ------------------------- // | id | protobuf message | // ------------------------- type Processor struct { littleEndian bool msgInfo []*MsgInfo msgID map[reflect.Type]uint16 } type MsgInfo struct { msgType reflect.Type msgRouter *chanrpc.Server msgHandler MsgHandler msgRawHandler MsgHandler } type MsgHandler func([]interface{}) func (p *Processor) SetRouter(msg proto.Message, msgRouter *chanrpc.Server) { msgType := reflect.TypeOf(msg) id, ok := p.msgID[msgType] if !ok { log.Fatal("message %s not registered", msgType) } p.msgInfo[id].msgRouter = msgRouter }
msgType := reflect.TypeOf(msg)
//leaf/network/protobuf.go的Register方法 i := new(MsgInfo) i.msgType = msgType p.msgInfo = append(p.msgInfo, i) id := uint16(len(p.msgInfo) - 1) p.msgID[msgType] = id return id
msgType := reflect.TypeOf(msg)reflect.Type
现在说一下执行顺序:
Processor.Register skeleton.RegisterChanRPC msg.Processor.SetRouter(&msg.Test{}, game.ChanRPC)
具体是怎么转交的,可以看一下protobuf的Router方法
func (p *Processor) Route(msg interface{}, userData interface{}) error { // raw if msgRaw, ok := msg.(MsgRaw); ok { if msgRaw.msgID >= uint16(len(p.msgInfo)) { return fmt.Errorf("message id %v not registered", msgRaw.msgID) } i := p.msgInfo[msgRaw.msgID] if i.msgRawHandler != nil { i.msgRawHandler([]interface{}{msgRaw.msgID, msgRaw.msgRawData, userData}) } return nil } // protobuf msgType := reflect.TypeOf(msg) id, ok := p.msgID[msgType] if !ok { return fmt.Errorf("message %s not registered", msgType) } i := p.msgInfo[id] if i.msgHandler != nil { i.msgHandler([]interface{}{msg, userData}) } if i.msgRouter != nil { i.msgRouter.Go(msgType, msg, userData) } return nil }
.Go(msgType, msg, userData)
func (a *agent) Run() { for { data, err := a.conn.ReadMsg() if err != nil { log.Debug("read message: %v", err) break } if a.gate.Processor != nil { msg, err := a.gate.Processor.Unmarshal(data) if err != nil { log.Debug("unmarshal message error: %v", err) break } err = a.gate.Processor.Route(msg, a) if err != nil { log.Debug("route message error: %v", err) break } } } }
.Go(msgType, msg, userData)
func handleTest(args []interface{}) { // 收到的 Test 消息 m := args[0].(*msg.Test) // 消息的发送者 a := args[1].(gate.Agent) ...
第一个正是msg,第二个是Agent接口,因为agent没暴露,agent实现了Agent接口,所以暴露的是Agent接口。