编写第一个 service 成功了,接下来考虑多个 service 之间如何通讯的问题。css
skynet 是单进程多线程框架,每一个 lua service 独立运行在本身的 lua vm 里,采用 actor 并发模型。git
这篇博客要实现的是让一个 service 发送消息,另外一个 service 处理消息。github
Actor模型又称为参与者模型,基本理念是每一个并发的线程(或者进程、服务等其余并发的东西)都是一个参与者,参与者之间互相发送消息,决定如何回应消息或者启动更多参与者。bootstrap
用人话来讲,就是参与者给另外一个参与者发送消息,而后继续干本身的事情;收到消息的参与者决定要怎么处理消息:作点什么,建立新参与者,或者抛弃这个消息。api
依照前文配置 skynet服务器
修改project/service/main.lua
。网络
-- main.lua local skynet = require "skynet" skynet.start(function() -- print("Hello world") skynet.newservice "myservice/worker" skynet.newservice "myservice/msg_dispatcher" skynet.exit() end)
主要修改的地方是加入了两行skynet.newservice
session
api参考文档在这里多线程
确实挺简陋的,就一句话。并发
newservice(name, ...) 启动一个名为 name 的新服务。
name
参数注意用相对于project/service
的路径便可,不用加lua
的后缀名。
在project/service
里建立目录myservice
,而后在里面建立新文件msg_dispatcher.lua
-- msg_dispatcher.lua local skynet = require "skynet" function sendmsg() skynet.send("worker", "lua", "say", "Hello world!") skynet.timeout(100, sendmsg) end skynet.start(function() skynet.timeout(100, sendmsg) end)
其中 function skynet.timeout(ti, func)
是定时器,第一个参数是时间,单位是 1/100 秒,第二个参数是回调函数。
而后是function skynet.send(addr, type, ...)
,第一个addr
是服务的地址,这个地址能够是服务的32位整数识别id,也能够是字符串别名;别名须要该服务自行注册才能使用。第二个type
参数是消息类型,经常使用的就是lua
虽然我也不知道为啥经常使用但你们都这么用。后面的变长参数通常来讲第一个约定是命令类型,再日后是命令参数,看下面的处理就知道了。
在project/service/myservice
里建立文件worker.lua
,而后这么写。
-- work.lua local CMD = {} CMD.say = function (text) print(text) end skynet.start(function() skynet.register("worker") skynet.dispatch("lua", function(session, source, cmd, ...) print("[worker] received `"..cmd.."`") local f = CMD[cmd] end) end)
几个api的介绍以下。
register(name)
给当前服务起一个字符串名。dispatch(type, func)
为 type 类型的消息设定一个处理函数。回调函数的签名是这样:
function (session, source, ...)
其中dispatch
的回调函数前两个参数分别是这样解释。
session
是为了确保能将消息处理结果对应到某条消息,就像是服务器收到同一个客户端的2条网络请求,一条请求js一条请求css,若是谁先处理完谁就返回的话,可能css的请求就收到了js的内容。source
是消息的来源,是一个整数id。后面的 cmd 参数其实也属于变长参数的一部分,可是通常约定变长参数第一个参数是服务要执行的命令 (RPC的感受),因此就给了个 cmd 的名字。变长参数剩余的部分就是处理函数的参数了。
固然用其余处理方法也没问题,只是经常使用模式。
[:00000001] LAUNCH logger [:00000002] LAUNCH snlua bootstrap [:00000003] LAUNCH snlua launcher [:00000004] LAUNCH snlua cdummy [:00000005] LAUNCH harbor 0 4 [:00000006] LAUNCH snlua datacenterd [:00000007] LAUNCH snlua service_mgr [:00000008] LAUNCH snlua main [:00000009] LAUNCH snlua myservice/msg_dispatcher [:0000000a] LAUNCH snlua myservice/worker [:00000008] KILL self [:00000002] KILL self [room_mgr] received `say` from `10` Hello world! [room_mgr] received `say` from `10` Hello world! [room_mgr] received `say` from `10` Hello world!