第一个程序PingPong

独一无二~ / 2023-08-21 / 原文

功能需求

如图所示,开启两个ping类型的服务ping1和ping2,ping1给ping2发消息,ping2收到回应ping1,ping1收到再回应ping2,不断循环。

服务模块

Skynet提供了开启服务发送消息的API,必先掌握它们。表2-5列出了Skynet中8个最重要的API,PingPong程序会用到它们。更多API可以参见 Skynet API

Lua API 说明
newservice(name,...)

启动一个名(类型)为name的新服务,并返回新服务的地址,地址格式为:0100000f、01000009即表示服务地址,同节点内的服务会有唯一地址,例如

local ping1 = skynet.newservice("ping")

表示开启一个ping类型的服务,把地址存放到ping1中

start(func) 用func函数初始化服务。编写服务时,都会写一名skynet.start,并在func写一些初始化代码
dispatch(type,func)

为type类型的消息设定处理函数fun。Skynet支持多种消息类型,由于Lua服务间的消息类型是“lua”,因此这里暂时将它固定为“lua”。func是指收到消息的处理函数,当一个服务收到新消息时,Skynet就会开启新协程,并调用它。func的形式为

function(session, source, cmd,...)

......

end

参数 session 代表消息的唯一id,source代表消息来源,指发送消息的服务地址,cmd代表消息号,"..."是一个可变参数,内容由发送方的skynet.send 或 skynet.call 指定

编写服务,一般会用如下的固定形式。表示以匿名函数的方式编写 skynet.start的参数func,并在func中调用dispatch

skynet.start(function()

  skynet.dispatch("lua",function(参数略)

    ......

  end)

end)

  send(addr,type,cmd,...)

向地址为addr的服务发送一条type类型的消息,消息名为cmd。发送方用skynet.send发送消息,接收文用skynet.dispatch接收消息,它们的参数相互对应。若用于服务间通信,类型一般固定为"lua" 例如,使用如下语句向服务 ping1 发送消息

skynet.send(ping1, "lua", "ping", 1, 2)

在ping1的dispatch回调中,参数的值如下

function(session, source, cmd, p1, p2, p3)

-- cmd = "ping"

-- p1 = 1

-- p2 = 2

-- p3 = nil

end

call(addr,type,cmd,...) 向地址为addr的服务发送一条type类型的消息,并等待对方的回应。skynet.call是个阻塞方法
exit() 结束当前服务
self() 返回当前服务的地址
error(msg) 向log服务发送一条消息,即打印日志

 

skynet.call的示意图

 

代码实现

PingPong程序必须包含主服务和ping服务。

配置文件(examples/Pconfig)

include "./config.path"

-- preload = "./preload.lua"    -- run preload.lua before every lua service run
thread = 8
logger = nil
logpath = "."
harbor = 1
address = "127.0.0.1:2526"
master = "127.0.0.1:2013"
start = "Pmain" -- main script
bootstrap = "snlua bootstrap"   -- The service for bootstrap
standalone = "0.0.0.0:2013"
-- snax_interface_g = "snax_g"
cpath = root.."cservice/?.so"
-- daemon = "./skynet.pid"

 

入口代码(examples/Pmain.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)

 

逻辑代码(examples/ping.lua)

local skynet = require "skynet"
local CMD = {}

function CMD.start(source, target)
  skynet.error("[ping] start..")
  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


skynet.start(function()
  skynet.dispatch("lua", function(session, source, cmd, ...)
          skynet.error("[ping] dispatch cmd="..cmd)
          if not CMD[cmd] then
            skynet.error("[ping] dispatch CMD[cmd] nil")
            return
          end
          local f = assert(CMD[cmd])
          f(source, ...)
  end)
end)

 

运行代码

root@server-VirtualBox:/home/skynet# ./skynet examples/Pconfig 
[:01000002] LAUNCH snlua bootstrap
[:01000003] LAUNCH snlua launcher
[:01000004] LAUNCH snlua cmaster
[:01000004] master listen socket 0.0.0.0:2013
[:01000005] LAUNCH snlua cslave
[:01000005] slave connect to master 127.0.0.1:2013
[:01000004] connect from 127.0.0.1:49210 4
[:01000006] LAUNCH harbor 1 16777221
[:01000004] Harbor 1 (fd=4) report 127.0.0.1:2526
[:01000005] Waiting for 0 harbors
[:01000005] Shakehand ready
[:01000007] LAUNCH snlua datacenterd
[:01000008] LAUNCH snlua service_mgr
[:01000009] LAUNCH snlua Pmain
[:01000009] [Pmain] start
[:0100000a] LAUNCH snlua ping
[:0100000b] LAUNCH snlua ping
[:01000009] KILL self
[:0100000a] [ping] dispatch cmd=start
[:0100000a] [ping] start..
[:01000002] KILL self
[:0100000b] [ping] dispatch cmd=ping
[:0100000b] [16777227] recv ping count=1
[:0100000a] [ping] dispatch cmd=ping
[:0100000a] [16777226] recv ping count=2
[:0100000b] [ping] dispatch cmd=ping
[:0100000b] [16777227] recv ping count=3
[:0100000a] [ping] dispatch cmd=ping
[:0100000a] [16777226] recv ping count=4
[:0100000b] [ping] dispatch cmd=ping
[:0100000b] [16777227] recv ping count=5
[:0100000a] [ping] dispatch cmd=ping
[:0100000a] [16777226] recv ping count=6