skynet lua服务callback执行过程

  1. lua服务都是通过snlua启动的,snlua服务启动时,最终会通过skynet.start把回调函数设为skynet.dispatch_message。
  2. 当有消息到达时,先调用到skynet.dispatch_message, 这里面再调到raw_dispatch_message
local function raw_dispatch_message(prototype, msg, sz, session, source, ...)
    if prototype == skynet.PTYPE_RESPONSE 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

这个函数会先判断消息类型是否是Response类型的(向别的服务发起一次RPC调用后,别的服务返回的消息)。

Response类型的消息

如果是Respone,则直接从session_id_coroutine表内根据session取出co(协程), 这里面的值是在发起RPC调用前把co缓存进去的,具体位置在:

function suspend(co, result, command, param, size)
    ...
    if command == "CALL" then
        session_id_coroutine[param] = co
    ...
end

取到co后,调用coroutine.resume(co, true, msg, sz)唤醒协程。


其他消息

如果不是Respone,则走正常的消息响应流程。

首先去proto表内找下有没有这个协议类型,proto表是调用skynet.register_protocol注册的,默认会注册lua,response,error三种类型的协议:

-- skynet.lua line 562
----- register protocol
do
    local REG = skynet.register_protocol

    REG {
        name = "lua",
        id = skynet.PTYPE_LUA,
        pack = skynet.pack,
        unpack = skynet.unpack,
    }

    REG {
        name = "response",
        id = skynet.PTYPE_RESPONSE,
    }

    REG {
        name = "error",
        id = skynet.PTYPE_ERROR,
        unpack = function(...) return ... end,
        dispatch = _error_dispatch,
    }
end

如果没找到相应的协议类型,判断下session是否等于0,如果不等于0就给源服务回一个error, 否则调用unknown_request。

如果有对应的协议,则取出其dispatch函数(这个函数是调用skynet.dispatch函数注册的,也可以在register_protocol时直接指定)。

取出dispatch函数后,这个函数就是真正要执行的消息回调函数了,但不是直接执行的,而是创建一个协程去执行,看下面的代码:

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, ...)))

这个co_create函数,可以简单理解成coroutine.create, (其实它里面维护了一个协程池,详细说明

创建完协程后,把session和source存起来,然后调用resume唤醒协程,开始执行回调函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值