版权声明:本文为作者原创,如需转载请通知本人,并标明出处和作者。擅自转载的,保留追究其侵权的权利。golang群:570992072。qq 29185807 个人公众号:月牙寂道长 公众号微信号yueyajidaozhang https://cloud.tencent.com/developer/article/1454498
本文公众号链接为:https://mp.weixin.qq.com/s/bzh3jZJkz96WxbPX4zF75A
Leaf 是一个由 Go 语言(golang)编写的开发效率和执行效率并重的开源游戏服务器框架。Leaf 适用于各类游戏服务器的开发,包括 H5(HTML5)游戏服务器。
阅读中文文档,其中介绍的是
leaf/chanrpc 提供了一套基于 channel 的 RPC 机制,用于游戏服务器模块间通讯。chanrpc提供了三种模式
那么下面看源码
源码目录为:
先看看github.com/name5566/leaf/chanrpc/example_test.go,里面演示了chanrpc的具体用法
chanrpc分为server和client两个部分
以上代码中是server的一个过程
1、初始化了一个server。
2、接着,注册了server提供的rpc函数。rpc支持三种类型
func([]interface{}) 参数为[]interface,无返回值
func([]interface{}) interface{} 参数为[]interface,返回值为interface
func([]interface{}) []interface{} 参数为[]interface,返回值为[]interface
3、最后server开启Exec执行rpc函数
以上为client过程
1、创建了client
2、同步调用。提供了集中调用方法。可以根据返回值分类来记忆:
Call0,Call1,CallN
3、异步调用。异步与同步的区别在于,异步执行调用完就会直接返回,但其注册了cb(call back)回调函数。在最后会等待异步执行完毕后,执行cb
4、Go模式。和异步调用的区别就是无cb。也是立即返回的。
用法分析完后,看具体的源码
github.com/name5566/leaf/chanrpc/chanrpc.go
基本数据结构RetInfo
ret interface{} 记录返回值,有三种类型
err error 记录err
cb interface{} 保存上下文中的Call back函数
基本数据结构CallInfo
f interface{} rpc调用的函数
args []interface{} 参数
chanRet chan *RetInfo 传递ret的chan
cb interface{} 保存上下文中的Call back函数
Server
Server数据结构
functions map[interface{}]interface{} 用于保存注册rpc函数
ChanCall chan *CallInfo 用于接收rpc调用chan
以上是Server初始化。注意其中l,是chancall的容量,意味着,异步调用时候能够异步传递多少函数。
Register
以上是注册接口(注意:此处并非线程安全的)
1、通过switch来对类型做一个判断。default中,则是不支持的类型,将会panic
2、判断是否重复注册
3、注册,其实就是放到map中。
Exec
回顾下用法
在github.com/name5566/leaf/chanrpc/example_test.go中
从以上代码中可以看出,就是从ChanCall中,取出CallInfo信息,然后执行。
继续跟踪
根据不同的rpc函数类型,封装不同的RetInfo。继续跟踪
1、当client调用的时候,没有注册chanret时,也就是为nil,不需要传递返回值,则直接返回不处理。否则继续往下处理
2、将client调用rpc时候,注册的cb,传递到RetInfo中。并将RetInfo发送到CallInfo中的chanRet中,将ret信息和cb传递给client。
到此Server所处理的流程都已经完了
Client
s *Server 对应的Server
chanSyncRet chan *RetInfo 同步调用时候,用于接收ret的chan
ChanAsynRet chan *RetInfo 异步调用的时候,用于接收ret和cb的chan
pendingAsynCall int 异步调用的计数器
初始化
两种模式
1、先初始化client结构体。这里要注意的是
同步chanSyncRet容量为1
异步cahnAsynRet的容量是初始化为参数l的。
2、将其Attach,附属到server中。其实就是将s初始化到client中的成员变量s
这种模式需要调用两次函数
这种模式,是将初始化和Attach封装到了一起。
同步调用
步骤是一样的
1、查找函数f
2、远程调用call。其中chanRet赋值的是chanSyncRet,block设置为true。这个是区别于异步调用模式的。
3、从chanSyncRet中接收ret,并将ret返回给上一层
f函数,功能就是一个,从server的注册函数中,查找到对应id的函数,将其返回。
其中做了一些函数的检查。
call函数:将CallInfo信息通过server的chancall发送给server。
1、同步模式,会阻塞等待
2、异步模式,会直接发送。如果chancall的容量不够,则会直接执行default。
在NewServer的时候,有个参数l,就是用来设置chancall的容量的。
异步调用
上述步骤
1、参数分割,最后一个参数是cb
2、对cb函数,类型检查,不支持的函数的话,则panic
3、判断异步调用是不是超出了异步chanAsynRet的容量,如果是,则直接将err返回
4、调用asynCall,并计数pendingAsynCall
以上步骤
1、从f中查找对应id的rpc函数。如果未查到,则直接通过chanAsynRet将err返回
2、call,这里面chanRet赋值的是chanAsynRet。blcok设置为false。这是区别于同步调用的。
异步执行结果
通过RetInfo中获取到cb函数,通过不同类型,进行cb调用。三种类型如下
ri.cb.(func(error))(ri.err)
ri.cb.(func(interface{}, error))(ri.ret, ri.err)
ri.cb.(func([]interface{}, error))(assert(ri.ret), ri.err)
Go模式
其实这个模式是最简单的
1、查找对应id的rpc函数
2、构建CallInfo发送到chancall中
不需要构建返回,也没有cb
close
还有一个没讲解的那就是close
server close
1、会先将chancall关闭掉
2、处理chancall中剩余的rpc调用。并不会执行,而是执行返回错误
client close
同步的是不用处理的,肯定会处理结束
主要的是异步的,异步有个计数器,会一直处理等待计数器为0
龚浩华
月牙寂道长
QQ 29185807
2018年04月17日