skynet框架應用 (八) Multicast組播

8 Multicast組播

8.1 Multicast介紹

local mc = require "skynet.multicast"

​ 引入 multicast 模塊後,你可以使用 skynet 的組播方案。你可以自由創建一個頻道,並可以向其中投遞任意消息。頻道的訂閱者可以收到投遞的消息。

​ 你可以通過 new 函數來創建一個頻道對象。你可以創建一個新頻道,也可以利用已知的頻道 id 綁定一個已有頻道。

local channel = mc.new()  -- 創建一個頻道,成功創建後,channel.channel 是這個頻道的 id 。
local channel2 = mc.new {
  channel = channel.channel,  -- 綁定上一個頻道
  dispatch = function (channel, source, ...) end,  -- 設置這個頻道的消息處理函數
}

​ 如上面的例子,new 函數可以接收一個參數表。channel 是頻道 id ,dispatch 是訂閱消息的回調函數。如果你不給出 channel id ,則新創建出一個頻道來。

​ 通常,由一個服務創建出頻道,再將 .channel 這個 id 通知別的地方。獲得這個 id 的位置,都可以綁定這個頻道。

channel:publish(...) 可以向一個頻道發佈消息。消息可以是任意數量合法的 lua 值。

​ 綁定到一個頻道後,默認並不接收這個頻道上的消息(也許你只想向這個頻道發佈消息)。你需要先調用 channel:subscribe() 訂閱它。

​ 如果不再想收到該頻道的消息,調用 channel:unsubscribe

​ 當一個頻道不再使用,你可以調用 channel:delete() 讓系統回收它。注:多次調用 channel:delete 是無害的,因爲 channel id 不會重複使用。在頻道被銷燬後再調用 subscribe 或 publish 等也不會引起異常,但訂閱是不起作用的,消息也不再廣播。

8.2 應用組播技術

示例代碼推送端:multicastpub.lua

local skynet = require "skynet"
local mc = require "skynet.multicast"
local channel

function task()
  local i = 0
  while(i < 100) do
    skynet.sleep(100)
    channel:publish("data"..i) --推送數據
    i = i + 1
  end
  channel:delete()
  skynet.exit()
end
skynet.start(function()
    channel = mc.new()  -- 創建一個頻道,成功創建後,channel.channel 是這個頻道的 id 。
    skynet.error("new channel ID", channel.channel)
    skynet.fork(task)
end)

示例代碼接受端:multicastsub.lua

local skynet = require "skynet"
local mc = require "skynet.multicast"
local channel
local channelID = ...  --從啓動參數獲取channelID
channelID = tonumber(channelID)

local function recvChannel(channel, source, msg, ...)
    skynet.error("channel ID:",channel, "source:", skynet.address(source), "msg:",msg)
end
skynet.start(function()
     channel = mc.new {
        channel = channelID, -- 綁定上一個頻道
        dispatch = recvChannel,  -- 設置這個頻道的消息處理函數
    }
    channel:subscribe()
    skynet.timeout(500, function() channel:unsubscribe() end) --5秒鐘後取消訂閱
end)

運行結果:

$ ./skynet examples/config
multicastpub #終端輸入
[:01000010] LAUNCH snlua multicastpub
[:01000012] LAUNCH snlua multicastd
[:01000010] new channel ID 1 #channel ID爲1
multicastsub 1  #終端輸入
[:01000019] LAUNCH snlua multicastsub 1
[:01000019] channel ID: [Multicast:1] source: :01000010 msg: data5
[:01000019] channel ID: [Multicast:1] source: :01000010 msg: data6
[:01000019] channel ID: [Multicast:1] source: :01000010 msg: data7
[:01000019] channel ID: [Multicast:1] source: :01000010 msg: data8
[:01000019] channel ID: [Multicast:1] source: :01000010 msg: data9 #5秒鐘後不再訂閱

8.3 組播原理

​ 當只考慮一個進程時,由於同一進程共享地址空間。當發佈消息時,由同一節點內的一個 multicastd 服務接收這條消息,並打包成一個 C 數據結構(包括消息指針、長度、引用計數),並把這個結構指針分別發送給同一節點的接收者。

​ 雖然這並沒有減少消息的數量、但每個接受者只需要接收一個數據指針。當組播的消息較大時,可以節省內部的帶寬。引用計數會在每個接收者收到消息後減一、最終由最後一個接收者銷燬。注:如果一個訂閱者在收到消息、但沒有機會處理它時就退出了。則有可能引起內存泄露。少量的內存泄露影響不大,所以 skynet 沒有特別處理這種情況。

​ 當有多個節點時,每個節點內都會啓動一個 multicastd 服務。它們通過 DataCenter 相互瞭解。multicastd 管理了本地節點創建的所有頻道。在訂閱階段,如果訂閱了一個遠程的頻道,當前節點的 multicastd 會通知遠程頻道的管理方,在該頻道有發佈消息時,把消息內容轉發過來。涉及遠程組播,不能直接共享指針。這時,multicastd 會將消息完整的發送到接收方所屬節點上的同僚,由它來做節點內的組播。


發佈了101 篇原創文章 · 獲贊 117 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章