srvSprotoAgent.lua 5.1 KB

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