skynet框架 源碼分析 四

本章主要講解:skynet的組播服務是怎麼發生的,如何運用。

        組播這個過程主要涉及了以下幾個服務。
        group_mgr,group_agent,multicast,tunnel,localcast。

        group_mgr是每個服務器集羣只有一個(即多個進程共有一個)。
        group_agent是每個harbor(即一個進程)只有一個。
        multicast。每次組播過程會生成兩個multicast服務,一個服務用來發送消息(接下來稱其爲send服務),一個服務用來接受來自其他harbor的消息(接下來稱其爲recv服務)。這兩個服務中,組員大體相同,不過,send服務比recv服務多一些成員,send組中有額外的tunnel服務成員。圖解:


        tunnel是一個記錄別的harbor上recv服務的服務。例如,假如有一個組ID爲10,在harbor1上有一個組員,在harbor2上有一個組員,那麼會在harbor1上生成一個tunnel服務指向harbor2上的組ID爲10的recv組服務。這樣在harbor1上給組10發廣播的時候,harbor2的成員也能收到消息。

        運行service文件夾下的testgroup.lua文件,啓動一個測試組播的服務。讓我們來讀源碼:

[plain] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. local skynet = require "skynet"  
  2. local group = require "mcgroup"  
  3.   
  4. skynet.start(function()  
  5.     local gid = group.create()  
  6.     local gaddr = group.address(gid)  
  7.     local g = {}  
  8.     print("=== Create Group ===",gid,skynet.address(gaddr))  
  9.     for i=1,10 do  
  10.         local address = skynet.newservice("testgroup_c", tostring(i))  
  11.         table.insert(g, address)  
  12.         group.enter(gid , address)  
  13.     end  
  14.     skynet.cast(g,"text","Cast")  
  15.     skynet.sleep(1000)  
  16.     skynet.send(gaddr,"text","Hello World")  
  17.     skynet.exit()  
  18. end)  

        首先,引入mcgroup庫。mcgroup,庫會啓動全局組播服務group_mgr,和本harbor的group_agent服務。
        group.create會向group_mgr申請一個組號ID(此文假設其爲A組)。
        group.address是獲取ID組的發送服務地址,在這裏面會生成一個multicast服務,也就是send服務,並將send服務的handle賦值gaddr。
        for循環中,開啓了10個組播模擬服務,這個我就不解釋了。看一下group.enter在幹什麼。

[plain] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. function group.enter(id, handle)  
  2.     handle = handle or skynet.self()  
  3.     skynet.send(SERVICE, "lua" , "ENTER", handle, id)  
  4. end  

        向全局group_mgr發送進入某個組的請求。也就是將生成的testgroup_c服務添加到A組的send服務中。不過在此過程中繼續看group_mgr的源碼。

[plain] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. -- 爲某個harbor上創建接收服務,並將其添加到其他harbor上,  
  2. -- 同時將別的harbor上的接受該廣播組的服務添加到本harbor上  
  3. local function create_group_in(harbor, id)    
  4.     local group_agent = assert(harbor_ctrl[harbor])  
  5.     local g = multicast[id]  
  6.     g[harbor] = false     
  7.     -- 在某個harbor上創建這個組的接受服務  
  8.     local receive_group_addr = skynet.call(group_agent, "lua", "CREATE", id)  
  9.     -- 向將別的組的接收地址註冊到本組管理器中  
  10.     for _,mc in pairs(g) do  
  11.         if mc then            
  12.             skynet.send(group_agent, "lua", "AGENT", id, mc)  
  13.         end  
  14.     end  
  15.     -- 向別的組發送當前接收組的地址  
  16.     for harbor_id, f_group_agent in pairs(harbor_ctrl) do  
  17.         if harbor_id ~= harbor then  
  18.             skynet.send(f_group_agent, "lua", "AGENT", id, receive_group_addr  
  19.         end  
  20.     end  
  21.     -- g跟組id值有關係,全都是各個harbor的接收組地址  
  22.     -- 一個組有一個g(multicast[id])表,g表中 harbor_id = 組(第id個組的地址)接收組地址  
  23.     g[harbor] = receive_group_addr    
  24. end  
  25.   
  26. function command.ENTER(address, harbor, id)  
  27.     local g = multicast[id]  
  28.     assert(g,id)  
  29.     if g[harbor] == nil then  
  30.         create_group_in(harbor, id)  
  31.     end  
  32.     local group_agent = assert(harbor_ctrl[harbor])  
  33.   
  34.     skynet.send(group_agent, "lua", "ENTER", id, address)  
  35. end  

        首先,我們把當前harbor命名爲harbor1,把其他的harbor命名爲harborN。

        開始讀代碼。在group_mgr的ENTER接口中,做了兩件事情,第一件:將自己的recv服務通過另外一個的harbor(稱其爲harbor2)的group_agent,添加到harbor2上。在harbor2上是如何做到的呢。我們繼續讀代碼,發現harbor2上的group_agent在收到消息後,會爲A組生成一個並生成一個tunnel服務指向harbor1上的recv服務,而後將tunnel添加到A組關聯的send服務,若在harbor2上沒有send服務,就生成一個;第二件事:就是將當前的testgroup_c服務添加到本harbor的send服務和recv服務中。(這其中會有一個問題,加入harbor2上沒有A組的成員,我覺得就沒辦法在harbor2上想A組發送廣播消息。)

        在經過這以後,我們獲得了兩個組播服務,分別是recv服務,和send服務。而後,簡單的看下一下面這句源碼

[plain] view plain copy
 print?在CODE上查看代碼片派生到我的代碼片
  1. skynet.send(gaddr,"text","Hello World")  

        其實就是像send服務發送一條廣播消息,hello world。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章