官术网_书友最值得收藏!

2.3 第一個程序PingPong

服務向另一個服務發送消息,是Skynet的最核心功能。PingPong是個很簡單的程序,下面用它來學習如何開啟服務、如何發送消息。

2.3.1 功能需求

如圖2-10所示,開啟兩個ping類型的服務ping1和ping2,讓ping1給ping2發消息,ping2收到后回應ping1,ping1收到再回應ping2,不斷循環。PingPong與1.7.2節的Actor程序“相互督促工作,努力賺錢”很相似。

圖2-10 PingPong程序示意圖

2.3.2 學習服務模塊

Skynet提供了開啟服務和發送消息的API,必先掌握它們。表2-5列出了Skynet中8個最重要的API,PingPong程序會用到它們。更多API可以參見https://github.com/cloudwu/skynet/wiki/APIList,此處暫不列舉太多,用到時再做介紹。

表2-5 Skynet中8個最重要的API

圖2-11 skynet.call的示意圖

2.3.3 代碼實現

初看API文檔可能一頭霧水,結合代碼才能融會貫通。按照2.3.1節的需求,PingPong程序必須包含主服務和ping服務。

1.主服務

新建文件examples/Pmain.lua,主服務如代碼2-2所示。

代碼2-2 examples/Pmain.lua中的主服務代碼

(資源:Chapter2/2_pingpong_main.lua)


local skynet = require "skynet"
skynet.start(function()
    skynet.error("[Pmain] start")
    local ping1 = skynet.newservice("ping")
    local ping2 = skynet.newservice("ping")
    
    skynet.send(ping1, "lua", "start", ping2)
    skynet.exit()
end)

說明:可以用Vim等工具直接在Linux上編輯文檔,也可以使用WinSCP、Samba等工具在Windows上編輯。

圖2-12是代碼2-2的示意圖,主服務啟動服務后,會先打印“[Pmain]start”(沒特別的作用,用于驗證程序是否運行到skynet.start的回調函數了),然后開啟兩個ping類型的服務,它們的地址分別存為ping1和ping2。再調用skynet.send,讓主服務向ping1發送名為“start”的消息(圖中的階段①),附帶一個參數ping2。最后,主服務完成使命,退出。

圖2-12 代碼2-2的示意圖

為使Skynet啟動Pmain,需設置配置文件。在examples中新建配置文件Pconfig,可以復制原先的Config文件,并將其中的start="main"改為start="Pmain"。Skynet會找到Pmian.lua作為主服務。也可以復制2.2.2節的配置模板,同樣,設置主服務為Pmain。

2.ping服務

新建文件examples/ping.lua,編寫ping服務。Skynet服務的基礎結構如代碼2-3所示(主服務功能單一,因此使用更簡單的寫法)。

代碼2-3 examples/ping.lua中的ping服務代碼

(資源:Chapter2/2_pingpong_ping.lua)


local skynet = require "skynet"

local CMD = {}

skynet.start(function()
    skynet.dispatch("lua", function(session, source, cmd, ...)
      local f=assert(CMD[cmd])
      f(source,...)
    end)
end)

在代碼2-3中,先用skynet.start初始化服務,然后在回調方法中調用skynet.dispatch,指定lua類型消息的處理方法。為使代碼簡潔,兩個回調方法都使用了匿名函數。代碼中帶底紋的兩句值得重點關注,其含義是:收到其他服務的消息后,查找CMD[cmd]這個方法是否存在,如果存在就調用它。例如,當ping1服務收到主服務的“start”消息時,程序會調用CMD.start(source, ...)。其中,參數source代表消息來源,其他參數由發送方傳送。

ping服務可以接收兩種消息:一種是主服務發來的start消息;另一種是其他ping服務發來的ping消息。如代碼2-4展示了這兩種消息的處理方法。

代碼2-4 examples/ping.lua中的ping服務消息處理


function CMD.start(source, target)
    skynet.send(target, "lua", "ping", 1)
end

function CMD.ping(source, count)
    local id = skynet.self()
    skynet.error("["..id.."] recv ping count="..count)
    skynet.sleep(100)
    skynet.send(source, "lua", "ping", count+1)
end

主服務會在啟動兩個ping服務后給ping1發送start消息,語句是“skynet.send(ping1, "lua", "start", ping2)”,最后一個參數對應CMD.start的參數target,代表要讓ping1發消息給誰。ping1收到后,會給ping2發送一條ping消息,附帶參數“1”。ping2收到后,執行CMD.ping,參數“1”對應參數count。ping2也會給ping1(發送方source)發送ping,并把記數值count加1,如此往復。

代碼中的skynet.sleep(100)指讓協程(ping方法)暫停1秒,這僅僅為了降低程序運行速度,讓讀者可以看清日志。

2.3.4 運行結果

執行./skynet examples/Pconfig運行程序,結果如圖2-13所示。其中0100000b和16777227代表ping2的地址(一個十六進制一個十進制,它們是相同的值,根據不同配置,讀者看到的數值可能不同),0100000a和16777226代表ping1的地址。ping2先打印出計數值1,接著ping1打印出計數值2,然后ping2再打印出計數值3,以此類推。

圖2-13 PingPong程序的運行結果

主站蜘蛛池模板: 赤峰市| 商都县| 光泽县| 从江县| 安阳县| 达尔| 忻州市| 聊城市| 慈利县| 灵丘县| 赤水市| 三都| 东乡| 遵化市| 新民市| 东丰县| 梨树县| 皋兰县| 南涧| 宁陕县| 栾城县| 安平县| 高邑县| 桑日县| 克拉玛依市| 资兴市| 西乌珠穆沁旗| 钦州市| 光泽县| 贵阳市| 铅山县| SHOW| 卢氏县| 武安市| 大石桥市| 新营市| 海阳市| 离岛区| 历史| 隆化县| 历史|