skynet_笔记

skynet 相关笔记

APIList:https://github.com/cloudwu/skynet/wiki/APIList

LuaAPI:https://github.com/cloudwu/skynet/wiki/LuaAPI


skynet.register(“login”)


切记事项

  • 不能用 lua 自带的 print, 否则会崩溃。具体原因还没查

获取本服务名称

  • SERVICE_NAME

修改 rpc 解析

登陆服

游戏服


消息重定向

  • 例如调用在 gateserver.lua 中需要将客户端的消息 重定向 到 agent.lua ,可以调用这个api

    1
    skynet.redirect (agent, 0, "client", 0, msg, sz)

    要使 msg 重定向到 agent 中,有两个前置条件

    1. gateserver.lua 中注册一个 client 协议,例如这样就可以了

      1
      2
      3
      4
      skynet.register_protocol {
      name = "client",
      id = skynet.PTYPE_CLIENT,
      }
    2. agent.lua 中同样需要一个注册一个 client 协议

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      skynet.register_protocol { 
      name = "client",
      id = skynet.PTYPE_CLIENT,
      unpack = function (msg, sz)
      print("------ 终于来带这里解析了, msg:", type(msg))
      return host:dispatch (msg, sz) -- 客户端使用的sproto,所以这里用sproto解码
      end,
      dispatch = function (source, session, type, ...)
      print("------ 终于来带这里解析了 222, type:", type(type))
      if type == "REQUEST" then
      handle_request (...) -- 处理客户端的请求
      elseif type == "RESPONSE" then
      handle_response (...) -- 处理请求客户端后的响应(客户端返回)
      else
      syslog.warningf ("invalid message type : %s", type)
      kick_self ()
      end
      end,
      }
  • 如果少了第一步,会报错:

    1
    2
    3
    [:00000016] lua call [0 to :16 : 0 msgsz = 24] error : ../3rd/skynet/lualib/skynet.lua:534: ../3rd/skynet/lualib/skynet.lua:156: ../3rd/skynet/lualib/skynet.lua:377: attempt to index a nil value (field '?')
    stack traceback:
    ../3rd/skynet/lualib/skynet.lua:377: in function 'skynet.redirect'

关于 gateserver.lua 中 msg 是 c 指针问题

  • 如果需要接入自己的 rpc 协议解析,必然要使用的这个 msg,但是这里的 msg 是个 c 指针。官方提供了一个 api: netpack.tostring 可以把这个 msg 转成 string 流,然后就可以按你自己的方式去处理这个消息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    local netpack = require "skynet.netpack"
    local function my_read_msg(fd, msg, sz)
    local msg = netpack.tostring(msg, sz)
    local proto_id, params = string.unpack(">Hs2", msg)
    local proto_name = msg_define.id_2_name(proto_id)
    local paramTab = Utils.str_2_table(params)
    print("--- proto_name:", proto_name)
    print("--- params:", params)
    return proto_name, paramTab
    end

关于 socket.lua 的使用

  • 由于里面有注册 socket 协议, 所以不能在 自定义的服务中 再次注册 socket 协议

    1
    2
    3
    4
    5
    6
    7
    8
    skynet.register_protocol {
    name = "socket",
    id = skynet.PTYPE_SOCKET, -- PTYPE_SOCKET = 6
    unpack = driver.unpack,
    dispatch = function (_, _, t, ...)
    socket_message[t](...)
    end
    }
    • 之前踩的坑:gateserver.lua 中有注册 socket 协议,但又想包读信息的分装到一个单独文件 proto_process.lua 中,里面有 require “skynet.socket” ,所以报错

      1
      2
      3
      4
      5
      [:00000016] lua loader error : ../3rd/skynet/lualib/skynet.lua:39: -------------- exit name:socket
      stack traceback:
      [C]: in function 'assert'
      ../3rd/skynet/lualib/skynet.lua:39: in function 'skynet.register_protocol'
      ./lualib/gameserver/gateserver.lua:127: in function 'gameserver.gateserver.start'

游戏服登陆分析

断线重连

  • 必然是先关闭 socket

挤号重登

  • socket 还在时,需要发给客户端 “已在其他地方登陆的提示”,然后主动断掉socket,新 socket 分配 agent

定时器

  • 时间间隔 3s,2s后执行

    1
    2
    3
    4
    5
    local function timer( ... )
    print("--- timer ", skynet.now())
    skynet.timeout(300, timer)
    end
    skynet.timeout(200, timer)
  • 测试代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    function cancelable_timeout(ti, func)
    local function cb()
    if func then
    func()
    end
    end
    local function cancel()
    func = nil
    end
    skynet.timeout(ti, cb)
    return cancel
    end

    local cancel = nil
    print("--- timer test")
    local counter = 0
    local function timer( ... )
    counter = counter + 1
    print("--- timer ", skynet.now())
    if counter == 3 then
    cancel()
    else
    skynet.timeout(200, timer)
    end
    end
    -- skynet.timeout(0, timer)
    cancel = cancelable_timeout(0, timer)

控制台调试