上兩篇skynet主體流程, skynet怎么啟動(dòng)lua文件介紹了skynet代碼的主體流程,還有怎么啟動(dòng)lua邏輯.
我們知道skynet業(yè)務(wù)邏輯都是在lua里寫的,這樣大大提高了開發(fā)效率,而且使熱更新成為可能,究竟lua層是怎么保證邏輯正常運(yùn)行,一個(gè)服務(wù)在lua層的表現(xiàn)形式又是怎么樣的呢?這篇將為您講解.
一個(gè)服務(wù)在lua層的入口是skynet.start(),他的實(shí)現(xiàn)為:
function skynet.start(start_func)
c.callback(skynet.dispatch_message) --①
skynet.timeout(0, function() --②
skynet.init_service(start_func)
end)
end
①這里是在c接口里指定服務(wù)的lua層回調(diào)函數(shù)dispatch_message,上篇我們有講到過.
②是通過timeout接口來間接執(zhí)行服務(wù)的入口函數(shù)
timeout的實(shí)現(xiàn):
function skynet.timeout(ti, func)
local session = c.intcommand("TIMEOUT",ti) -- ①
assert(session)
local co = co_create(func) -- ②
assert(session_id_coroutine[session] == nil)
session_id_coroutine[session] = co
end
① 調(diào)用c的timeout接口,他會(huì)產(chǎn)生一個(gè)session id
② 啟動(dòng)協(xié)程池,關(guān)聯(lián)func,session Id
c接口的timeout的實(shí)現(xiàn):
1 根據(jù)context產(chǎn)生一個(gè)該context遞增的session id
2 如果參數(shù)time==0,產(chǎn)生一條PTYPE_RESPONSE類型的消息壓入隊(duì)列;如果不為0,則增加時(shí)間節(jié)點(diǎn)
由于上面的參數(shù)是0,則產(chǎn)生一條PTYPE_RESPONSE類型的消息,包含了session id
當(dāng)消息隊(duì)列捕獲并執(zhí)行該消息的時(shí)候,就會(huì)調(diào)用lua層的回調(diào)函數(shù)skynet.dispatch_message了,最終調(diào)用raw_dispatch_message.它的實(shí)現(xiàn):
local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
-- skynet.PTYPE_RESPONSE = 1, read skynet.h
if prototype == 1 then
local co = session_id_coroutine[session] ①
if co == "BREAK" then
session_id_coroutine[session] = nil
elseif co == nil then
unknown_response(session, source, msg, sz)
else
session_id_coroutine[session] = nil
suspend(co, coroutine.resume(co, true, msg, sz)) --②
end
else
local p = proto[prototype]
if p == nil then
if session ~= 0 then
c.send(source, skynet.PTYPE_ERROR, session, "")
else
unknown_request(session, source, msg, sz, prototype)
end
return
end
local f = p.dispatch
if f then
local ref = watching_service[source]
if ref then
watching_service[source] = ref + 1
else
watching_service[source] = 1
end
local co = co_create(f)
session_coroutine_id[co] = session
session_coroutine_address[co] = source
suspend(co, coroutine.resume(co, session,source, p.unpack(msg,sz, ...)))
else
unknown_request(session, source, msg, sz, proto[prototype].name)
end
end
end
timeout產(chǎn)生的消息執(zhí)行時(shí)會(huì)走分支①,他的session關(guān)聯(lián)了一個(gè)協(xié)程,他是在timeout中調(diào)用co_create()產(chǎn)生的. co_create()是為了復(fù)用協(xié)程而產(chǎn)生的,具體請(qǐng)參考這篇:lua協(xié)程池
找到session關(guān)聯(lián)的協(xié)程后,②開始執(zhí)行suspend(co, corutine.resume(co,...)),實(shí)際上是先執(zhí)行了corutine.resume(co),啟動(dòng)協(xié)程,執(zhí)行了協(xié)程里的函數(shù),即timeout傳入的函數(shù).suspend函數(shù)用來對(duì)協(xié)程的調(diào)度和調(diào)配,為了突出主干,下篇再講suspend函數(shù).至此一個(gè)服務(wù)的入口函數(shù)就通skynet.start()調(diào)用起來了