srvGate.lua 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. local skynet = require "skynet"
  2. require "skynet.manager"
  3. local socket = require "skynet.socket"
  4. local websocket = require "http.websocket"
  5. local socketdriver = require "skynet.socketdriver"
  6. local jmutil = require "jmutil"
  7. local WATCHDOG = nil
  8. local mapFd = {} -- fd -> connection : { fd , client, agent , ip, mode }
  9. local clientCount = 0
  10. local MAX_CLIENT = 1024 -- max client
  11. local IS_NODELAY = false
  12. -- fd解绑agent
  13. local function l_unband_agent(c)
  14. if c.agent then
  15. c.agent = nil
  16. c.client = nil
  17. end
  18. end
  19. local function l_close_fd(fd)
  20. local c = mapFd[fd]
  21. if c then
  22. l_unband_agent(c)
  23. mapFd[fd] = nil
  24. clientCount = clientCount - 1
  25. end
  26. end
  27. local handler = {}
  28. -- 接受链接
  29. function handler.connect(fd)
  30. local addr = websocket.addrinfo(fd)
  31. skynet.error(string.format("ws connect fd[%s] from[%s] ", tostring(fd), tostring(addr)))
  32. if clientCount >= MAX_CLIENT then
  33. -- 超出最大承载玩家数
  34. socketdriver.close(fd)
  35. skynet.error(string.format("超出最大承载玩家数 MAX_CLIENT[%s]", tostring(MAX_CLIENT)))
  36. return
  37. end
  38. if IS_NODELAY then
  39. socketdriver.nodelay(fd)
  40. end
  41. clientCount = clientCount + 1
  42. local c = {
  43. fd = fd,
  44. ip = addr
  45. }
  46. mapFd[fd] = c
  47. skynet.send(WATCHDOG, "lua", "socket", "open", fd, addr)
  48. end
  49. function handler.handshake(fd, header, url)
  50. end
  51. -- 接收消息
  52. function handler.message(fd, msg)
  53. -- skynet.error("message ws ping from: " .. tostring(fd), msg.."\n")
  54. if #msg == 0 then
  55. return
  56. end
  57. -- msg is string
  58. local data, sz = jmutil.str2lightuserdata(msg)
  59. -- recv a package, forward it
  60. local c = mapFd[fd]
  61. local agent = c and c.agent
  62. if agent then
  63. skynet.redirect(agent, c.client, "client", fd, data, sz)
  64. else
  65. -- 首次必须鉴权
  66. skynet.send(WATCHDOG, "lua", "socket", "data", fd, data, sz)
  67. end
  68. end
  69. function handler.ping(fd)
  70. skynet.error("ws ping from: " .. tostring(fd) .. "\n")
  71. end
  72. function handler.pong(fd)
  73. skynet.error("ws pong from: " .. tostring(fd))
  74. end
  75. function handler.close(fd, code, reason)
  76. skynet.error("ws close from: " .. tostring(fd), code, reason)
  77. l_close_fd(fd)
  78. skynet.send(WATCHDOG, "lua", "socket", "close", fd)
  79. end
  80. function handler.error(fd)
  81. skynet.error("ws error from: " .. tostring(fd))
  82. l_close_fd(fd)
  83. skynet.send(WATCHDOG, "lua", "socket", "error", fd)
  84. end
  85. function handler.warning(fd, size)
  86. skynet.send(WATCHDOG, "lua", "socket", "warning", fd, size)
  87. end
  88. local root = {}
  89. -- 开始监听链接
  90. function root.open(source, conf)
  91. WATCHDOG = conf.watchdog or source
  92. if conf.maxclient then
  93. MAX_CLIENT = conf.maxclient
  94. end
  95. IS_NODELAY = conf.nodelay
  96. -- 打开监听链接端口
  97. local address = "0.0.0.0"
  98. local port = assert(conf.wsPort)
  99. local protocol = conf.protocol or "ws"
  100. local fd = socket.listen(address, port)
  101. skynet.error(
  102. string.format("Listen websocket fd[%s] port[%s] protocol[%s]", tostring(fd), tostring(port), tostring(protocol))
  103. )
  104. -- 开始接受链接
  105. socket.start(
  106. fd,
  107. function(fd, addr)
  108. -- skynet.error(string.format("accept client socket_fd: %s addr:%s", fd, addr))
  109. websocket.accept(fd, handler, protocol, addr)
  110. end
  111. )
  112. end
  113. -- fd已经绑定agent
  114. function root.fd_band_agent(source, fd, client, address)
  115. if not mapFd[fd] then
  116. return false
  117. end
  118. local c = assert(mapFd[fd])
  119. l_unband_agent(c)
  120. c.client = client or 0
  121. c.agent = address or source
  122. return true
  123. end
  124. -- 向fd回应消息
  125. function root.send_to_client(source, fd, msg)
  126. if msg == nil then
  127. return
  128. end
  129. websocket.write(fd, msg, "binary")
  130. end
  131. -- 断开链接
  132. function root.kick(source, fd)
  133. websocket.close(fd)
  134. end
  135. -- 注册接收skynet协议列表
  136. skynet.register_protocol {
  137. name = "client",
  138. id = skynet.PTYPE_CLIENT
  139. }
  140. skynet.start(
  141. function()
  142. skynet.dispatch(
  143. "lua",
  144. function(session, source, cmd, ...)
  145. local f = root[cmd]
  146. if not f then
  147. skynet.error("wsGate can't dispatch cmd " .. (cmd or nil))
  148. return
  149. end
  150. if session == 0 then
  151. f(source, ...)
  152. else
  153. skynet.ret(skynet.pack(f(source, ...)))
  154. end
  155. end
  156. )
  157. skynet.register(".ws_gate")
  158. end
  159. )