1. 程式人生 > >skynet框架應用 (五) 服務別名

skynet框架應用 (五) 服務別名

5 服務別名
​    每個服務啟動之後,都有一個整形數來表示id,也可以使用字串id來表示,例如::01000010,其實就是把id:0x01000010轉換成字串。

​    但是這個數字的表示方式會根據服務的啟動先後順序而變化,不是一個固定的值。如果想要方便的獲取某個服務,那麼可以通過給服務設定別名來。

5.1 本地別名與全域性別名
​    在skynet中,服務別名可以分為兩種:

一種是本地別名,本地別名只能在當前skynet節點使用,本地別名必須使用. 開頭,例如:.testalias

一種是全域性別名,全域性別名可以在所有skynet中使用,全域性別名不能以. 開頭, 例如:testalias


5.2 別名註冊與查詢介面

------------------------------[[取別名]]--------------------------
local skynet = require "skynet"
require "skynet.manager"

--給當前服務定一個別名,可以是全域性別名,也可以是本地別名
skynet.register(aliasname)

--給指定servicehandler的服務定一個別名,可以是全域性別名,也可以是本地別名
skynet.name(aliasname, servicehandler)
-------------------------------------------------------------------

----------------------[[查詢別名]]------------------------------
--查詢本地別名為aliasname的服務,返回servicehandler,不存在就返回nil
skynet.localname(aliasname)

--[[
查詢別名為aliasname的服務,可以是全域性別名也可以是本地別名,
1、當查詢本地別名時,返回servicehandler,不存在就返回nil
2、當查詢全域性別名時,返回servicehandler,不存在就阻塞等待到該服務初始化完成
]]--
local skynet = require "skynet.harbor"
harbor.queryname(aliasname)
-------------------------------------------------------------------


注意:本地別名與全域性別名可以同時存在。

5.3 給服務註冊別名
5.3.1給普通服取別名
示例程式碼:testalias.lua


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()

    local handle = skynet.newservice("test")

    skynet.name(".testalias", handle)   --給服務起一個本地別名
    skynet.name("testalias", handle)    --給服務起一個全域性別名
    
    
    handle = skynet.localname(".testalias")    
    skynet.error("localname .testalias handle", skynet.address(handle))
    
    handle = skynet.localname("testalias")      --只能查本地,不能查全域性別名      
    skynet.error("localname testalias handle", skynet.address(handle))
    
    handle = harbor.queryname(".testalias")             
    skynet.error("queryname .testalias handle", skynet.address(handle))
    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))
  

end)


上面服務通過skynet.newservice來啟動一個test.lua服務,test.lua程式碼如下:


local skynet = require "skynet" 
skynet.start(function()
    skynet.error("My new service")
end)

執行結果:


$ ./skynet examples/config
testalias #執行main.lua後在終端輸入
[:0100000a] LAUNCH snlua testalias
[:0100000b] LAUNCH snlua test
[:0100000b] My new service
[:0100000a] localname .testalias handle :0100000b   #skynet.localname查到本地名
[:0100000a] localname testalias handle nil          #skynet.localname查不到全域性名
[:0100000a] queryname .testalias handle :0100000b   #harbor.queryname查到本地名
[:0100000a] queryname testalias handle :0100000b    #harbor.queryname查到全域性名

5.3.2 全域性別名查詢阻塞
​    如果全域性別名不存在,那麼這個時候呼叫函式harbor.queryname,將會阻塞,直到全域性別名的服務建立成功。

示例程式碼:testalias.lua


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()
        
    handle = skynet.localname(".testalias")    --查詢本地別名不阻塞
    skynet.error("localname .testalias handle", skynet.address(handle))
    
    handle = skynet.localname("testalias")      --無法查詢全域性別名
    skynet.error("localname testalias handle", skynet.address(handle))
    
    handle = harbor.queryname(".testalias")     --查詢本地別名不阻塞 
    skynet.error("queryname .testalias handle", skynet.address(handle))
    
    handle = harbor.queryname("testalias")      --查詢全域性別名阻塞       
    skynet.error("queryname testalias handle", skynet.address(handle))
  

end)

執行結果:


$ ./skynet examples/config                                             
testalias
[:0100000a] LAUNCH snlua testalias
[:0100000a] localname .testalias handle nil #skynet.localname查到本地名
[:0100000a] localname testalias handle nil  #skynet.localname查不到全域性名
[:0100000a] queryname .testalias handle nil #harbor.queryname查到本地名
                                        #harbor.queryname查不到全域性名, 函式阻塞

5.3.3 多節點中的全域性別名
​    啟動兩個skynet節點,在節點1取別名,節點2查詢別名:

節點1,testaliasname.lua


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()
    local handle = skynet.newservice("test")
    skynet.name(".testalias", handle)   --給服務起一個本地別名
    skynet.name("testalias", handle)    --給服務起一個全域性別名
end)
節點2, testaliasquery.lua


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()
    
    handle = skynet.localname(".testalias")              
    skynet.error("localname .testalias handle", skynet.address(handle))
    
    handle = skynet.localname("testalias")               
    skynet.error("localname testalias handle", skynet.address(handle))
    
    handle = harbor.queryname(".testalias")             
    skynet.error("queryname .testalias handle", skynet.address(handle))
    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))

end)

先啟動節點1執行testaliasname.lua,再啟動節點2執行


testaliasquery
[:0200000a] LAUNCH snlua testaliasquery
[:0200000a] localname .testalias handle nil
[:0200000a] localname testalias handle nil
[:0200000a] queryname .testalias handle nil
[:0200000a] queryname testalias handle :0100000b --查詢到節點1建立的服務

5.3.4 殺死帶別名的服務
​    給一個服務取了別名後,殺死它,本地別名將會登出掉,但是全域性別名依然存在,通過全域性別名查詢到的handle已經沒有意義。如果通過handle進行一些操作將得到不可預知的問題。


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()

    local handle = skynet.newservice("test")

    skynet.name(".testalias", handle)   --給服務起一個本地別名
    skynet.name("testalias", handle)    --給服務起一個全域性別名
    
    
    handle = skynet.localname(".testalias")              
    skynet.error("localname .testalias handle", skynet.address(handle))
    
    handle = skynet.localname("testalias")               
    skynet.error("localname testalias handle", skynet.address(handle))
    
    handle = harbor.queryname(".testalias")             
    skynet.error("queryname .testalias handle", skynet.address(handle))
    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))


    skynet.kill(handle) --殺死帶別名服務


    handle = skynet.localname(".testalias")              
    skynet.error("localname .testalias handle", skynet.address(handle))
    
    handle = skynet.localname("testalias")               
    skynet.error("localname testalias handle", skynet.address(handle))
    
    handle = harbor.queryname(".testalias")             
    skynet.error("queryname .testalias handle", skynet.address(handle))
    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))


end)
執行結果:


testalias
[:0100000a] LAUNCH snlua testalias
[:0100000b] LAUNCH snlua test
[:0100000b] My new service
[:0100000a] localname .testalias handle :0100000b
[:0100000a] localname testalias handle nil
[:0100000a] queryname .testalias handle :0100000b
[:0100000a] queryname testalias handle :0100000b
[:0100000a] KILL :100000b
[:0100000a] localname .testalias handle nil
[:0100000a] localname testalias handle nil
[:0100000a] queryname .testalias handle nil
[:0100000a] queryname testalias handle :0100000b #全域性別名還存在,但是已經殺死該服務了。
​    skynet的全域性別名服務是在cslave裡面實現的,現在不允許二次修改全域性別名繫結關係,所以全域性別名一般用來給一個永遠不會退出的服務來啟用。

​    但是有些情況下,我們確實需要二次修改全域性別名繫結關係,那麼這個時候,我們可以嘗試去修改一下cslave.lua檔案,修改內容如下:


function harbor.REGISTER(fd, name, handle)
    --assert(globalname[name] == nil)  --將這一行註釋掉
    globalname[name] = handle
    response_name(name)
    socket.write(fd, pack_package("R", name, handle))
    skynet.redirect(harbor_service, handle, "harbor", 0, "N " .. name)
end

執行一個二次修改全域性別名繫結關係的服務,例如:


local skynet = require "skynet" 
require "skynet.manager"
local harbor = require "skynet.harbor"

skynet.start(function()

    local handle = skynet.newservice("test")

    skynet.name("testalias", handle)    --給服務起一個全域性別名

    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))


    skynet.kill(handle) --殺死帶全域性別名服務
    handle = skynet.newservice("test")
    skynet.name("testalias", handle)    --全域性別名給其他服務使用
    
    handle = harbor.queryname("testalias")               
    skynet.error("queryname testalias handle", skynet.address(handle))


end)
執行結果:


testalias
[:0100000a] LAUNCH snlua testalias
[:0100000b] LAUNCH snlua test
[:0100000b] My new service
[:0100000a] queryname testalias handle :0100000b
[:0100000a] KILL :100000b
[:0100000c] LAUNCH snlua test
[:0100000c] My new service
[:0100000a] queryname testalias handle :0100000c   #服務別名二次修改成功

5.4 全域性別名與全域性唯一服名區別
​    全域性唯一服名與這裡的全域性別名是兩個概念的名詞。

​    全域性唯一服名稱: 是用來標識服務是唯一的,服務名稱一般就是指令碼名稱,無法更改。

​    全域性別名: 是用來給服務起別名的,既可以給普通服起別名,也可以給全域性唯一服起別名。

​    他們兩種名字是在不同的體系中的,有各種的起名字的方式,以及查詢的方式。

​    所以不要嘗試用skynet.queryservice查詢一個全域性別名,也不要嘗試使用harbor.queryname去查詢一個全域性唯一服。

例如:


    local handle = skynet.uniqueservice("test") --啟動一個全域性唯一服,名字為test
    
    handle = harbor.queryname("test")           --查不到的,會一直阻塞
或者:


    local handle = skynet.uniqueservice("test") --啟動一個全域性唯一服,名字為test

    skynet.name("testalias", handle)            --再起一個全域性別名
    
    handle = skynet.queryservice("testalias")   --查不到的,也會一直阻塞
--------------------- 
作者:嚇人的猿 
來源:CSDN 
原文:https://blog.csdn.net/qq769651718/article/details/79432868 
版權宣告:本文為博主原創文章,轉載請附上博文連結!