iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0
Software Development

在麥塊的農場裡寫 Lua系列 第 21

Day21 用更高階的網路框架實現更多功能

  • 分享至 

  • xImage
  •  

上一回介紹過 CC: Tweaked Wired Modem 和 Wireless Modem 的網路功能
事實上,這在 CC: Tweaked 裡頭是比較低階的網路實作
彈性比較大,但功能比較少

CC: Tweaked 其實已經幫我們包裝好這些底層實作,另提供一個較高階的網路 API: rednet
透過 rednet API 除了可以實現電腦之間傳訊的基本功能之外
還有一些進階功能,包括廣播、無限長度傳輸、訊息分類與過濾、限時傳送、主機定義
而且撰寫 rednet API 的程式碼,也比直接用底層 peripheral/modem API 來得少
以下我是直接閱讀 /rom/apis/rednet.lua 後,以底層的 peripheral API 來解釋,總結 rednet API 的用途

為了避免解釋複雜,我先總結兩個共通特性:

  1. rednet 預設都是以目前電腦 id 當作通訊 channel,也就是上一回我講的 modem 的 senderChannel
  2. rednet 定義 broadcast channel 編號為 65535, repeat channel 為 65533

全部 rednet API 的底層實作如下:

  • rednet.open( side )
    尋找 side 方向的數據機,並 open id channel,同時 open broadcast channel
  • rednet.close( [side] )
    關閉 side 方向的數據機的 id channel 和 broadcast channel。如果不給參數,就關閉所有 modem 的 channel
  • rednet.isOpen( [side] )
    判斷 side 方向的數據機是否有開啟 id channel 和 broadcast channel。如果不給參數,就判斷是否有任何數據機是 open,只要有一個數據機是 open 就回傳 true
  • rednet.send( receiverID, message, [protocol] )
    透過所有打開的數據機,傳送訊息給 receiverID(接收端電腦 id),而 replyChannel 則是目前電腦 id,同時也會傳送到 repeat channel
    而傳送的訊息會是一個 table 結構如下
    {
        nMessageID = nMessageID,  -- 亂數
        nRecipient = nRecipient,  -- receiverID
        message = message,        -- 真正的訊息內容
        sProtocol = sProtocol,    -- 過濾分類用的字串
    }
    
  • rednet.broadcast( message, [protocol] )
    廣播訊息,其作用等同於
    send(CHANNEL_BROADCAST, message, sProtocol)
  • rednet.receive( [protocol], [timeout] ) -- Returns: senderID, message, protocol
    根據 protocol 或是 timeout 接收訊息,有四種接收訊息的方式
    1. rednet.receive() 無限時間接收任何訊息
    2. rednet.receive(protocol) 無限時間,只接收屬於 protocol 類的訊息 (protocol 不為數字)
    3. rednet.receive(timeout) 在 timeout 時限內,接受任何訊息
    4. rednet.receive(protocol, timeout) 在 timeout 時限內,只接受屬於 protocol 類的訊息
  • rednet.host( protocol, hostname )
    這是方便玩家分類、定義主機類型與名稱,架設你在麥塊世界裡面搞個雲端平台,那真的要好好分類才是 XD
  • rednet.unhost( protocol )
    搭配 host 來管理主機
  • rednet.lookup( protocol, [hostname] ) -- Returns: ID
    方便玩家尋找特定 protocol, hostname 的電腦 id。這樣有個好處是管理龐大的主機群,並且在取得 id 之後,都用 rednet.send() 通訊即可,不要每次都 broadcast 浪費網路資源。這跟現實的網路世界實在很像 XD

CC: Tweaked Rednet 的無限距離傳輸

介紹過 Rednet API 的大概實作後,來實際 demo 吧,我們來解決上一回的問題:Wireless Modem 的最遠傳輸距離是 64 格方塊。
無限距離傳輸超級簡單,CC: Tweaked 也包裝好工具了
架設你想要傳輸 A -> E 中間大約距離 240 格方塊,那麼只要在這中間大約每隔 60 方塊距離放置一台電腦,各自安裝一台 Wireless Modem,開機後直接執行 repeat,之後就不用管了
示意如下,要執行 repeat 的有 B, C, D 電腦
A (60方塊)-> B (60方塊)-> C (60方塊)-> D (60方塊)-> E

repeat 就是 /rom/programs/rednet/repeat.lua
它做的事情就是一直不斷接收 Repeat channel 的訊息並轉發,所以理論上,只要你肯大約每隔 60 方塊就放置一台電腦做 repeat,傳輸可以無限遠

要測試的話,其實也不用急著寫 code
還記得 CC: Tweaked 有個互動式的 Lua 環境可以用嗎?
輸入 lua 即可,程式在 /rom/programs/lua.lua
首先要到遙遠的接收端開啟 rednet 並持續接收訊息

rednet.open("top")  -- 假設你數據機是放在上方
rednet.receive()    -- 不限制 protocol,不限時間接收訊息

接著回到傳送端電腦

rednet.open("top")  -- 假設你數據機是放在上方
rednet.send(19, "I love moon")  -- 你必須先知道接收端電腦的 id
rednet.broadcast("I love moon") -- 不知道 id 就先用 broadcast 試試

接收端的畫面收到訊息如下
CC: Tweaked Rednet Receive

中間作為中繼站的電腦,畫面如下
CC: Tweaked Rednet Repeat

最後,實際感受一下到底傳了多遠(遠目...
CC: Tweaked Rednet Repeat

今天就介紹到這裡,至於 protocol, hostname, timeout 的設計,真的就看玩家自己怎麼應用了
你也可以試試~


上一篇
Day20 讓電腦透過數據機和有線、無線網路傳遞訊息
下一篇
Day22 高階網路應用 GPS 和 Ender Modem
系列文
在麥塊的農場裡寫 Lua30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言