skynet.newservice:
skynet.newservice
时,它会每次都创建一个新的服务实例,即使之前已经存在相同类型的服务实例。local service1 = skynet.newservice("my_service")
local service2 = skynet.newservice("my_service")
skynet.uniqueservice:
skynet.uniqueservice
时,它会检查是否已经存在相同类型的服务实例。如果已经存在,则返回已存在的服务实例的句柄,而不会启动新的实例。local service1 = skynet.uniqueservice("my_service")
local service2 = skynet.uniqueservice("my_service") -- 返回与service1相同的句柄
该函数是用于将一组 Lua 值打包成一个二进制字符串的接口。这个接口在底层用于消息的序列化和打包,通常在网络传输、进程间通信等场景中使用。
具体来说,pack
函数接受一组 Lua 值作为参数,并返回一个包含了这些值的二进制字符串。这个字符串可以通过网络或其他方式传递给其他服务或系统组件。
例如:
local c = require "skynet.core"
local data = c.pack(42, "hello", {1, 2, 3})
-- 将 data 发送给其他服务,用于消息传递或通信
在上述例子中,pack
将整数 42、字符串 "hello" 和一个包含数字的数组打包成一个二进制字符串,并将其存储在变量 data
中。
在 Skynet 中,这样的打包操作常常用于将消息序列化,以便通过网络或消息队列传递给其他 Skynet 服务。反之,unpack
函数用于将这样的二进制字符串反序列化为 Lua 值。
请注意,pack
和 unpack
通常是 Skynet 框架内部使用的底层接口。在一般的 Skynet 服务代码中,您更可能会使用高级的接口,如 skynet.send
和 skynet.call
,它们会自动处理消息的序列化和反序列化。
在Skynet框架中,协程状态的概念通常与消息处理和异步操作密切相关。Skynet使用协程的方式实现了一种事件驱动的异步编程模型。除了"SUSPEND"状态之外,Skynet还定义了其他一些状态,它们对应于协程在不同的事件和阶段的处理。
以下是一些常见的协程状态:
"SUSPEND":表示协程被挂起,通常是因为它正在等待某个事件的发生或在执行异步操作。在这个状态下,协程通过coroutine.yield("SUSPEND")
挂起,等待外部事件或其他协程的唤醒。
"RUNNING":表示协程正在运行中,即处于活动状态。协程会在处理消息或执行其他任务时处于这个状态。通常,协程在运行中时不会被挂起。
"DEAD":表示协程已经终止或结束。协程在执行完任务后,或者在发生错误时可能会进入这个状态。已经结束的协程不再可用。
这些状态反映了协程在消息处理过程中的生命周期。在Skynet框架中,通过coroutine.yield
传递不同的状态,可以实现协程的挂起和恢复,以及在不同的状态下执行相应的处理逻辑。状态的具体用途可能因具体的业务逻辑而有所不同。
在 Skynet 框架中,c.callback()
是用于注册一个 C 函数(Callback Function)到 Skynet 的底层事件循环中的回调队列中。这样,当 Skynet 的事件循环需要执行回调函数时,它就会调用注册的 C 函数。
通常情况下,c.callback()
会在 C 模块的初始化部分调用,用于注册一些与底层事件循环相关的回调函数。这些回调函数可能用于处理网络事件、定时器、IO 等底层的异步操作。
这个函数的具体用途和效果可能依赖于具体的 Skynet 模块或 C 拓展,因为 Skynet 的底层是使用 C 实现的,并且提供了一些 C API 来与 Lua 交互。在 Skynet 的源码或相关文档中,可能会有详细的说明和用法示例。
总的来说,c.callback()
的作用是将一个 C 函数注册为 Skynet 事件循环的回调,以便在事件发生时执行这个 C 函数。如果您想了解具体的用法和效果,建议查阅 Skynet 的源码或文档。
下面以一个wsgate为例
local gate = skynet.uniqueservice("wsgate") -- 启动一个服务器实例,并返回句柄
3. 接着进入uniqueservice接口,发现里面是调用skynet.call
function skynet.uniqueservice(global, ...)
if global == true then
return assert(skynet.call(".service", "lua", "GLAUNCH", ...))
else
return assert(skynet.call(".service", "lua", "LAUNCH", global, ...)) -- 调用.call的时候,会把“LAUNCH”以及后面的数据打包发到底层C语言中去处理,C里面通过LAUNCH映射到cmd_launch
end
end
4.进入skynet.call,第一个if是判断要不要打印,这个无伤大雅先不管他;然后再去调用auxsend这个函数和下面的挂起协程
function skynet.call(addr, typename, ...)
local tag = session_coroutine_tracetag[running_thread]
if tag then
c.trace(tag, "call", 2)
c.send(addr, skynet.PTYPE_TRACE, 0, tag)
end
local p = proto[typename]
local session = auxsend(addr, p.id , p.pack(...)) -- auxsend接口:调用c.cend接口发送消息(其次做了会话冲突处理)
if session == nil then
error("call to invalid address " .. skynet.address(addr))
end
return p.unpack(yield_call(addr, session)) -- 挂起协程
end
5.现在去看下auxsend这个函数,这段代码比较长
dangerzone
是一个用于标记处于 "danger zone" 区域的集合,这个区域是一个会随着会话(session)递增而重新设置的区域。这里的 "danger zone" 是为了防止会话的递增与之前的某些会话发生冲突。set_checkrewind
和 set_checkconflict
是用于设置 auxsend
和 auxtimeout
的辅助函数,根据当前的会话范围选择合适的函数。checkconflict
函数用于检查会话是否存在冲突,即下一个会话是否已经存在。如果存在冲突,将会进行相应的处理,可能会调整 auxsend
和 auxtimeout
的实现,以确保不发生会话冲突。auxsend_checkconflict
和 auxtimeout_checkconflict
以及 auxsend_checkrewind
和 auxtimeout_checkrewind
是根据当前会话范围选择的具体的消息发送和超时设置的函数。它们会在发送消息或设置超时时检查是否存在冲突,如果存在冲突,则会进行相应的处理。auxsend
和 auxtimeout
被设置为 auxsend_checkrewind
和 auxtimeout_checkrewind
,表示在最初的 "safe zone" 区域中。总体来说,这段代码的目的是为了管理会话(session)的递增,并根据当前会话范围的不同来选择适当的消息发送和超时设置的实现。这有助于防止会话冲突,并在需要时进行相应的处理。
然后auxsend会被设置成auxsend_checkconflict或者auxsend_checkrewind,在这两个接口中调用csend接口调用skynet.core底层中的send函数。
TODO:至于为什么要做会话冲突处理,我的理解是怕每个会话的地址重复了,这个理解的还不是很到位,以后理解了再做补充。还有就是send到C语言那边是怎么做处理的,这个以后有空再补充
do ---- avoid session rewind conflict
local csend = c.send
local cintcommand = c.intcommand
local dangerzone
local dangerzone_size = 0x1000
local dangerzone_low = 0x70000000
local dangerzone_up = dangerzone_low + dangerzone_size
local set_checkrewind -- set auxsend and auxtimeout for safezone
local set_checkconflict -- set auxsend and auxtimeout for dangerzone
local function reset_dangerzone(session)
dangerzone_up = session
dangerzone_low = session
dangerzone = { [session] = true }
for s in pairs(session_id_coroutine) do
if s < dangerzone_low then
dangerzone_low = s
elseif s > dangerzone_up then
dangerzone_up = s
end
dangerzone[s] = true
end
dangerzone_low = dangerzone_low - dangerzone_size
end
-- in dangerzone, we should check if the next session already exist.
-- 检查会话是否存在冲突,即下一个会话是否已经存在。如果存在冲突,将会进行相应的处理,可能会调整 auxsend 和 auxtimeout 的实现,以确保不发生会话冲突。
local function checkconflict(session)
if session == nil then
return
end
local next_session = session + 1
if next_session > dangerzone_up then
-- leave dangerzone
reset_dangerzone(session)
assert(next_session > dangerzone_up)
set_checkrewind()
else
while true do
if not dangerzone[next_session] then
break
end
if not session_id_coroutine[next_session] then
reset_dangerzone(session)
break
end
-- skip the session already exist.
next_session = c.genid() + 1
end
end
-- session will rewind after 0x7fffffff
if next_session == 0x80000000 and dangerzone[1] then
assert(c.genid() == 1)
return checkconflict(1)
end
end
local function auxsend_checkconflict(addr, proto, msg, sz)
local session = csend(addr, proto, nil, msg, sz)
checkconflict(session)
return session
end
local function auxtimeout_checkconflict(timeout)
local session = cintcommand("TIMEOUT", timeout)
checkconflict(session)
return session
end
local function auxsend_checkrewind(addr, proto, msg, sz)
local session = csend(addr, proto, nil, msg, sz)
if session and session > dangerzone_low and session <= dangerzone_up then
-- enter dangerzone
set_checkconflict(session)
end
return session
end
local function auxtimeout_checkrewind(timeout)
local session = cintcommand("TIMEOUT", timeout)
if session and session > dangerzone_low and session <= dangerzone_up then
-- enter dangerzone
set_checkconflict(session)
end
return session
end
set_checkrewind = function()
auxsend = auxsend_checkrewind
auxtimeout = auxtimeout_checkrewind
end
set_checkconflict = function(session)
reset_dangerzone(session)
auxsend = auxsend_checkconflict
auxtimeout = auxtimeout_checkconflict
end
-- in safezone at the beginning
-- 默认是将auxsend设置成auxsend_checkrewind
set_checkrewind()
end
6.yield_call里面主要是将这个协程挂起,等待
local function yield_call(service, session)
watching_session[session] = service
session_id_coroutine[session] = running_thread
local succ, msg, sz = coroutine_yield "SUSPEND"
watching_session[session] = nil
if not succ then
error "call failed"
end
return msg,sz
end