srvSprotoAgent.lua 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. -- 网关agent
  2. local skynet = require "skynet"
  3. local protoUtil = require("utils.protoUtil")
  4. local nodeUtil = require("utils.nodeUtil")
  5. local CMD = {}
  6. local GATE, WATCHDOG
  7. local mapFd = {} -- MAP, key fd; value {uid=uid, heart=0}
  8. local mapUid2Session = {} -- MAP, key uid; value session
  9. -- 断开非活跃链接
  10. local function l_start_fd_heart_bit()
  11. skynet.fork(
  12. function(...)
  13. while true do
  14. for fd, v in pairs(mapFd) do
  15. if skynet_time() - v.heart >= 60 then
  16. skynet.send(WATCHDOG, "lua", "close", fd, "overTime")
  17. end
  18. end
  19. skynet.sleep(200) -- 20s
  20. end
  21. end
  22. )
  23. end
  24. local function l_request(fd, protoname, args, ...)
  25. local fdInfo = mapFd[fd]
  26. if fdInfo == nil or fdInfo.uid == nil then
  27. -- fd未绑定玩家
  28. return
  29. end
  30. local uid = fdInfo.uid
  31. local session = mapUid2Session[uid]
  32. if not session then
  33. return
  34. end
  35. -- 修改fd心跳时间
  36. fdInfo.heart = skynet_time()
  37. -- 转发给游戏服
  38. args.uid = args.uid or uid
  39. nodeUtil:send_to_node(session.gameNode, session.gameAgent, "c2s_forward", uid, protoname, args, ...)
  40. end
  41. local function l_dispath_msg(fd, msg)
  42. local ok, ptype, protoname, args, session, ud = pcall(protoUtil.decode_c2s_req_ex, protoUtil, msg)
  43. if not ok then
  44. return log.error("decode sproto faild")
  45. end
  46. if ptype ~= "REQUEST" then
  47. return log.error("This example doesn't support request client")
  48. end
  49. l_request(fd, protoname, args, session, ud)
  50. end
  51. -- 获取玩家fd
  52. local function l_get_user_fd(uid)
  53. if uid == nil then
  54. return
  55. end
  56. local session = mapUid2Session[uid]
  57. if session then
  58. return session.fd
  59. end
  60. end
  61. skynet.register_protocol {
  62. name = "client",
  63. id = skynet.PTYPE_CLIENT,
  64. unpack = skynet.tostring,
  65. dispatch = function(fd, address, msg)
  66. skynet.ignoreret()
  67. l_dispath_msg(fd, msg)
  68. end
  69. }
  70. -- from watchdog
  71. function CMD.login(uid, fd)
  72. GATE = GATE or skynet.queryservice("srvGate")
  73. WATCHDOG = WATCHDOG or skynet.queryservice("wsSprotoWatchdog")
  74. local session = mapUid2Session[uid]
  75. if session then
  76. if session.fd then
  77. mapFd[fd] = nil
  78. end
  79. session.fd = fd
  80. else
  81. -- 分配游戏服节点/agent
  82. local gameNode, gameAgent = nodeUtil:user_dispatch_game_node_and_agent(uid)
  83. log.info("login uid[%s] gameNode[%s] gameAgent[%s]", tostring(uid), tostring(gameNode), tostring(gameAgent))
  84. session = {
  85. fd = fd,
  86. uid = uid,
  87. gateNode = skynet.getenv("nodeName"),
  88. gateAgent = skynet.self(),
  89. gameNode = gameNode,
  90. gameAgent = gameAgent
  91. }
  92. end
  93. local fdInfo = {uid = uid, heart = skynet_time()}
  94. mapFd[fd] = fdInfo
  95. mapUid2Session[uid] = session
  96. -- 通知gameAgent 玩家登陆
  97. local ok = nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "login", uid, session)
  98. if not ok then
  99. log.error("uid:%s send game to login error", uid)
  100. return false
  101. end
  102. -- 接收客户端协议
  103. _, ok = pcall(skynet.call, GATE, "lua", "fd_band_agent", fd)
  104. if not ok then
  105. log.error("uid:%s send gate to fd_band_agent", tostring(uid))
  106. return false
  107. end
  108. nodeUtil:user_master_band_node(uid)
  109. return true
  110. end
  111. -- from watchdog
  112. function CMD.logout(uid)
  113. local session = mapUid2Session[uid]
  114. if not session then
  115. return
  116. end
  117. local fd = session.fd
  118. if fd then
  119. mapFd[fd] = nil
  120. end
  121. session.fd = nil
  122. -- 玩家登出
  123. nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "logout", uid, session)
  124. nodeUtil:user_master_unband_node(uid)
  125. if uid then
  126. mapUid2Session[uid] = nil
  127. end
  128. end
  129. -- 向玩家发消息
  130. function CMD.s2c(uid, name, msg)
  131. local fd = l_get_user_fd(uid)
  132. if fd == nil then
  133. return
  134. end
  135. -- log.proto("push uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
  136. local rs = protoUtil:encode_s2c_req(name, msg)
  137. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  138. end
  139. -- 回应客户端请求
  140. function CMD.c2s_response(uid, name, msg, session, ud)
  141. local fd = l_get_user_fd(uid)
  142. if fd == nil then
  143. return
  144. end
  145. -- log.proto("response uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
  146. local rs = protoUtil:encode_c2s_rsp_ex(name, msg, session, ud)
  147. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  148. end
  149. -- 踢玩家
  150. function CMD.kick(uid, msg)
  151. local fd = l_get_user_fd(uid)
  152. if fd == nil then
  153. return
  154. end
  155. -- 通知玩家被踢
  156. local rs = protoUtil:encode_s2c_req("on_server_code", msg)
  157. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  158. -- 关闭链接
  159. skynet.send(WATCHDOG, "lua", "close", fd, "kick")
  160. end
  161. function CMD.recycle()
  162. skynet.exit()
  163. end
  164. function CMD.update_proto()
  165. protoUtil.update()
  166. end
  167. skynet.start(
  168. function()
  169. skynet.dispatch(
  170. "lua",
  171. function(session, address, command, ...)
  172. local f = CMD[command]
  173. if session > 0 then
  174. skynet.ret(skynet.pack(f(...)))
  175. else
  176. f(...)
  177. end
  178. end
  179. )
  180. -- 心跳监听
  181. l_start_fd_heart_bit()
  182. end
  183. )