1、服务模块
Skynet提供了开启服务和发送消息的API,必须要先掌握它们。列出了Skynet中8个最重要的API,PingPong程序会用到它们。
Lua API | 说明 |
newservice(name, ...) | 启动一个名为 name 的新服务,并返回服务的地址。 |
start(func) | 用 func 函数初始化服务,并将消息处理函数注册到 C 层,让该服务可以工作。 |
dispatch(type, func) | 为 type 类型的消息设定一个处理函数。Skynet支持多种消息类型,由于Lua服务间的消息类型是“lua”,因此这里暂时将它定为“lua”。func是指收到消息后的处理函数,当一个服务收到消息时,skynet就会开启新协程,并调用它。 |
send(addr, type, ...) | 用 type 类型向 addr 发送一个消息,消息名为cmd。发送方用skynet.send发送消息,接收方用skynet.dispatch接受消息,它们的参数相互对应。若用于服务间通信,类型一般固定为“lua” |
call(addr, type, ...) | 用 type 类型发送一个消息到 addr ,并等待对方的回应。skynet.call是个阻塞方法。 |
exit() | 结束当前服务。 |
self() | 返回当前服务的地址。 |
error(msg) | 打印日志,向 log 服务发送一条消息。 |
更多API可以参见:https://github.com/cloudwu/skynet/wiki/APIList
2、程序开发
初看API文档可能一头雾水,结合下面的实例开发才能融会贯通。
按如下图所示,开启两个ping类型的服务ping1和ping2,让ping1给ping2发消息,ping2收到
后回应ping1,ping1收到再回应ping2,不断循环。
3、代码实现
(1)主服务
在skynet/examples目录下新建main_ping.lua文件,输入如下所示代码:
local skynet = require "skynet"
skynet.start(function()skynet.error("[PingMain] start")local ping1 = skynet.newservice("Ping")local ping2 = skynet.newservice("Ping")skynet.send(ping1, "lua", "start", ping2)skynet.exit()
end)
- 主服务启动服务后,会先打印“[PingMain]start”的日志输出;
- 然后开启两个ping类型的服务,它们的地址分别存为ping1和ping2;
- 再调用skynet.send,让主服务向ping1发送名 为“start”的消息(图中的阶段①),附带一个参数ping2;
- 最后,主服务完成使命,退出。
(2)ping服务
在skynet/examples目录下新建ping.lua文件,输入如下所示代码:
local skynet = require "skynet"local CMD = {}function CMD.start(source, target)skynet.send(target, "lua", "ping", 1)
endfunction CMD.ping(source, count)local id = skynet.self()skynet.error("["..id.."] recv ping count="..count)skynet.sleep(100)skynet.send(source, "lua", "ping", count+1)
endskynet.start(function()skynet.dispatch("lua", function(session, source, cmd, ...)local f = assert(CMD[cmd])f(source,...)end)
end)
为使代码简洁,两个回调方法都使用了匿名函数。代码说明:
- 先用skynet.start初始化服务;
- 然后在回调方法中调用skynet.dispatch,指定lua类型消息的处理方法,参数session代表消息的唯一id,可暂时先不管。source代表消息来源,指发送消息的服务地址,cmd代表消息名,“...”是一个可变参数,内容由发送方的skynet.send或skynet.call指定。
- 收到其他服务的消息后,查找CMD[cmd]这个方法是否存 在,如果存在就调用它;
- 当ping1服务收到主服务的“start”消息时,程序会调用CMD.start(source, ...)。其中,参数source代表消息来源,其他参数由发送方传送。
- ping服务可以接收两种消息:一种是主服务发来的start消息;另一种是其他ping服务发来的ping消息。
主服务会在启动两个ping服务后给ping1发送start消息,语句 是“skynet.send(ping1, "lua", "start", ping2)”,最后一个参数对应CMD.start的参数target,代表要让ping1发消息给谁。ping1收到后,会给ping2发送一条ping消息,附带参数“1”。ping2收到后,执行CMD.ping,参数“1”对应参数count。ping2也会给ping1(发送方 source)发送ping,并把记数值count加1,如此往复。
(3)配置文件
在skynet/examples目录下新建PingConfig文件,然后把config中的内容复制过来稍加修改,内容如下所示:
include "config.path"thread = 8
logger = nil
logpath = "."
harbor = 0
start = "main_ping" -- main script
bootstrap = "snlua bootstrap" -- The service for bootstrap
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"
(4)运行结果
最后打开终端,输入如下指令,显示运行结果。
其中0000000a和10代表ping2的地址(一个十六进制一个十进制,它们是相同的值,根据不
同配置,读者看到的数值可能不同),00000009和9代表ping1的地址。ping2先打印出计数值1,
接着 ping1打印出计数值2,然后ping2再打印出计数值3,以此类推。