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接口。