skynet源码分析:服务

skynet是为多人在线游戏打造的轻量级服务端框架,使用c+lua实现。使用这套框架的一个好处就是,基本只需要lua,很少用到c做开发,一定程度上提高了开发效率。

skynet的例子是怎么调用的
服务器: 
simpledb.lua: skynet.register “SIMPLEDB” 向skynet里注册一个服务 
agent.lua: skynet.call(“SIMPLEDB”, “text”, text) 调用相应的服务 
main.lua: skynet.newservice(“simpledb”) 启动一个服务
以上函数都在\lualib\skynet.lua 文件内
 

以下是几个写服务时经常要用到的函数。

newservice(name, ...) 启动一个名为 name 的新服务。
uniqueservice(name, ...) 启动一个唯一服务,如果服务该服务已经启动,则返回已启动的服务地址。
queryservice(name) 查询一个由 uniqueservice 启动的唯一服务的地址,若该服务尚未启动则等待。
localname(name) 返回同一进程内,用 register 注册的具名服务的地址。

newservice可以在一个进程里启动多个服务,这适用于无状态的服务。
uniqueservice则是类似于设计模式中的单件(singleton),这适用于需要唯一性的服务。举个例子,比如写日志,只想写一份。或者是全局共享的数据。
 
消息机制
SKYNET设计综述讲到模块被称为服务。“服务间可以自由发送消息。每个模块可以向 Skynet 框架注册一个 callback 函数,用来接收发给它的消息。”还提到“把一个符合规范的 C 模块,从动态库(so 文件)中启动起来,绑定一个永不重复(即使模块退出)的数字 id 做为其 handle 。Skynet 提供了名字服务,还可以给特定的服务起一个易读的名字,而不是用 id 来指代它。id 和运行时态相关,无法保证每次启动服务,都有一致的 id ,但名字可以。”今天要分析的两个文件skynet_handle.c和skynet_handle.h就是实现名字服务的。

skynet_handle.c实际上就做了两个核心的事情,一是给服务分配一个handle,二是把handle和name关联起来。

把handle和name关联起来比较容易懂,实际上使用一个数组,关联的时候使用二分查找到数组里查名字,如果名字不存在,就插入一个元素,然后把名字和handle关联起来。插入元素的时候,如果数组空间不足了,就扩容为原来的2倍。

而给服务分配handle稍复杂一些,实际上也是使用一个slot数组,数组下标使用的是一个hash,数组元素指向服务的上下文。这个hash的算法是比较简单粗暴的,就是看从handle_indx开始累计到slot_size,看中间有没有空闲的下标(也就是下标指向为null的),如果遍历完了还是没有,就把slot扩大一倍,还是没有就再扩大一倍,直到找到空位为止,或者是slot长度超出限制为止。

取到了handle以后呢,还要将harbor id附到handle的高8位。


参考:

skynet教程(3)--服务的别名

猜你喜欢

转载自www.cnblogs.com/losophy/p/9203060.html