srvSprotoAgent.lua 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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. if is_empty(gameNode) or is_empty(gameAgent) then
  85. return false
  86. end
  87. session = {
  88. fd = fd,
  89. uid = uid,
  90. gateNode = skynet.getenv("nodeName"),
  91. gateAgent = skynet.self(),
  92. gameNode = gameNode,
  93. gameAgent = gameAgent
  94. }
  95. end
  96. local fdInfo = {uid = uid, heart = skynet_time()}
  97. mapFd[fd] = fdInfo
  98. mapUid2Session[uid] = session
  99. -- 通知gameAgent 玩家登陆
  100. local ok = nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "login", uid, session)
  101. if not ok then
  102. log.error("uid:%s send game to login error", uid)
  103. return false
  104. end
  105. -- 接收客户端协议
  106. _, ok = pcall(skynet.call, GATE, "lua", "fd_band_agent", fd)
  107. if not ok then
  108. log.error("uid:%s send gate to fd_band_agent", tostring(uid))
  109. return false
  110. end
  111. nodeUtil:user_master_band_node(uid)
  112. return true
  113. end
  114. -- from watchdog
  115. function CMD.logout(uid)
  116. local session = mapUid2Session[uid]
  117. if not session then
  118. return
  119. end
  120. local fd = session.fd
  121. if fd then
  122. mapFd[fd] = nil
  123. end
  124. session.fd = nil
  125. -- 玩家登出
  126. nodeUtil:call_to_game_agent(session.gameNode, session.gameAgent, "logout", uid, session)
  127. nodeUtil:user_master_unband_node(uid)
  128. if uid then
  129. mapUid2Session[uid] = nil
  130. end
  131. end
  132. -- 向玩家发消息
  133. function CMD.s2c(uid, name, msg)
  134. local fd = l_get_user_fd(uid)
  135. if fd == nil then
  136. return
  137. end
  138. -- log.proto("push uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
  139. local rs = protoUtil:encode_s2c_req(name, msg)
  140. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  141. end
  142. -- 向所有玩家发消息
  143. function CMD.s2c_broadcast(name, msg)
  144. local rs = protoUtil:encode_s2c_req(name, msg)
  145. for fd, _ in pairs(mapFd) do
  146. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  147. end
  148. end
  149. -- 回应客户端请求
  150. function CMD.c2s_response(uid, name, msg, session, ud)
  151. local fd = l_get_user_fd(uid)
  152. if fd == nil then
  153. return
  154. end
  155. -- log.proto("response uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
  156. local rs = protoUtil:encode_c2s_rsp_ex(name, msg, session, ud)
  157. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  158. end
  159. -- 踢玩家
  160. function CMD.kick(uid, msg)
  161. local fd = l_get_user_fd(uid)
  162. if fd == nil then
  163. return
  164. end
  165. -- 通知玩家被踢
  166. local rs = protoUtil:encode_s2c_req("on_server_code", msg)
  167. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  168. -- 关闭链接
  169. skynet.send(WATCHDOG, "lua", "close", fd, "kick")
  170. end
  171. function CMD.recycle()
  172. skynet.exit()
  173. end
  174. function CMD.update_proto()
  175. protoUtil:update()
  176. end
  177. skynet.start(
  178. function()
  179. skynet.dispatch(
  180. "lua",
  181. function(session, address, command, ...)
  182. local f = CMD[command]
  183. if f == nil then
  184. log.error("agent command[%s] not found", tostring(command))
  185. end
  186. if session > 0 then
  187. skynet.ret(skynet.pack(f(...)))
  188. else
  189. f(...)
  190. end
  191. end
  192. )
  193. -- 心跳监听
  194. l_start_fd_heart_bit()
  195. end
  196. )