srvSprotoAgent.lua 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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.s2c_broadcast(name, msg)
  141. local rs = protoUtil:encode_s2c_req(name, msg)
  142. for fd, _ in pairs(mapFd) do
  143. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  144. end
  145. end
  146. -- 回应客户端请求
  147. function CMD.c2s_response(uid, name, msg, session, ud)
  148. local fd = l_get_user_fd(uid)
  149. if fd == nil then
  150. return
  151. end
  152. -- log.proto("response uid=%s, name=%s, msg=%s", uid, name, tostring(msg))
  153. local rs = protoUtil:encode_c2s_rsp_ex(name, msg, session, ud)
  154. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  155. end
  156. -- 踢玩家
  157. function CMD.kick(uid, msg)
  158. local fd = l_get_user_fd(uid)
  159. if fd == nil then
  160. return
  161. end
  162. -- 通知玩家被踢
  163. local rs = protoUtil:encode_s2c_req("on_server_code", msg)
  164. skynet.send(GATE, "lua", "send_to_client", fd, rs)
  165. -- 关闭链接
  166. skynet.send(WATCHDOG, "lua", "close", fd, "kick")
  167. end
  168. function CMD.recycle()
  169. skynet.exit()
  170. end
  171. function CMD.update_proto()
  172. protoUtil:update()
  173. end
  174. skynet.start(
  175. function()
  176. skynet.dispatch(
  177. "lua",
  178. function(session, address, command, ...)
  179. local f = CMD[command]
  180. if f == nil then
  181. log.error("agent command[%s] not found", tostring(command))
  182. end
  183. if session > 0 then
  184. skynet.ret(skynet.pack(f(...)))
  185. else
  186. f(...)
  187. end
  188. end
  189. )
  190. -- 心跳监听
  191. l_start_fd_heart_bit()
  192. end
  193. )