skynet 入门笔记(2):service 消息收发

Skynet 入门笔记(2):Service 消息收发

编写第一个 service 成功了,接下来考虑多个 service 之间如何通讯的问题。css

skynet 是单进程多线程框架,每一个 lua service 独立运行在本身的 lua vm 里,采用 actor 并发模型。git

这篇博客要实现的是让一个 service 发送消息,另外一个 service 处理消息。github

actor 并发模型

Actor模型又称为参与者模型,基本理念是每一个并发的线程(或者进程、服务等其余并发的东西)都是一个参与者,参与者之间互相发送消息,决定如何回应消息或者启动更多参与者。bootstrap

用人话来讲,就是参与者给另外一个参与者发送消息,而后继续干本身的事情;收到消息的参与者决定要怎么处理消息:作点什么,建立新参与者,或者抛弃这个消息。api

skynet 启动新 service

依照前文配置 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.newservicesession

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的介绍以下。

  1. register(name) 给当前服务起一个字符串名。
  2. dispatch(type, func) 为 type 类型的消息设定一个处理函数。

回调函数的签名是这样:

function (session, source, ...)

其中dispatch的回调函数前两个参数分别是这样解释。

  1. session是为了确保能将消息处理结果对应到某条消息,就像是服务器收到同一个客户端的2条网络请求,一条请求js一条请求css,若是谁先处理完谁就返回的话,可能css的请求就收到了js的内容。
  2. 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!
相关文章
相关标签/搜索