123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- local skynet = require "skynet"
- require "skynet.manager"
- local socket = require "skynet.socket"
- local websocket = require "http.websocket"
- local socketdriver = require "skynet.socketdriver"
- local jmutil = require "jmutil"
- local WATCHDOG = nil
- local mapFd = {} -- fd -> connection : { fd , client, agent , ip, mode }
- local clientCount = 0
- local MAX_CLIENT = 1024 -- max client
- local IS_NODELAY = false
- -- fd解绑agent
- local function l_unband_agent(c)
- if c.agent then
- c.agent = nil
- c.client = nil
- end
- end
- local function l_close_fd(fd)
- local c = mapFd[fd]
- if c then
- l_unband_agent(c)
- mapFd[fd] = nil
- clientCount = clientCount - 1
- end
- end
- local handler = {}
- -- 接受链接
- function handler.connect(fd)
- local addr = websocket.addrinfo(fd)
- skynet.error(string.format("ws connect fd[%s] from[%s] ", tostring(fd), tostring(addr)))
- if clientCount >= MAX_CLIENT then
- -- 超出最大承载玩家数
- socketdriver.close(fd)
- skynet.error(string.format("超出最大承载玩家数 MAX_CLIENT[%s]", tostring(MAX_CLIENT)))
- return
- end
- if IS_NODELAY then
- socketdriver.nodelay(fd)
- end
- clientCount = clientCount + 1
- local c = {
- fd = fd,
- ip = addr
- }
- mapFd[fd] = c
- skynet.send(WATCHDOG, "lua", "socket", "open", fd, addr)
- end
- function handler.handshake(fd, header, url)
- end
- -- 接收消息
- function handler.message(fd, msg)
- -- skynet.error("message ws ping from: " .. tostring(fd), msg.."\n")
- if #msg == 0 then
- return
- end
- -- msg is string
- local data, sz = jmutil.str2lightuserdata(msg)
- -- recv a package, forward it
- local c = mapFd[fd]
- local agent = c and c.agent
- if agent then
- skynet.redirect(agent, c.client, "client", fd, data, sz)
- else
- -- 首次必须鉴权
- skynet.send(WATCHDOG, "lua", "socket", "data", fd, data, sz)
- end
- end
- function handler.ping(fd)
- skynet.error("ws ping from: " .. tostring(fd) .. "\n")
- end
- function handler.pong(fd)
- skynet.error("ws pong from: " .. tostring(fd))
- end
- function handler.close(fd, code, reason)
- skynet.error("ws close from: " .. tostring(fd), code, reason)
- l_close_fd(fd)
- skynet.send(WATCHDOG, "lua", "socket", "close", fd)
- end
- function handler.error(fd)
- skynet.error("ws error from: " .. tostring(fd))
- l_close_fd(fd)
- skynet.send(WATCHDOG, "lua", "socket", "error", fd)
- end
- function handler.warning(fd, size)
- skynet.send(WATCHDOG, "lua", "socket", "warning", fd, size)
- end
- local root = {}
- -- 开始监听链接
- function root.open(source, conf)
- WATCHDOG = conf.watchdog or source
- if conf.maxclient then
- MAX_CLIENT = conf.maxclient
- end
- IS_NODELAY = conf.nodelay
- -- 打开监听链接端口
- local address = "0.0.0.0"
- local port = assert(conf.wsPort)
- local protocol = conf.protocol or "ws"
- local fd = socket.listen(address, port)
- skynet.error(
- string.format("Listen websocket fd[%s] port[%s] protocol[%s]", tostring(fd), tostring(port), tostring(protocol))
- )
- -- 开始接受链接
- socket.start(
- fd,
- function(fd, addr)
- -- skynet.error(string.format("accept client socket_fd: %s addr:%s", fd, addr))
- websocket.accept(fd, handler, protocol, addr)
- end
- )
- end
- -- fd已经绑定agent
- function root.fd_band_agent(source, fd, client, address)
- if not mapFd[fd] then
- return false
- end
- local c = assert(mapFd[fd])
- l_unband_agent(c)
- c.client = client or 0
- c.agent = address or source
- return true
- end
- -- 向fd回应消息
- function root.send_to_client(source, fd, msg)
- if msg == nil then
- return
- end
- websocket.write(fd, msg, "binary")
- end
- -- 断开链接
- function root.kick(source, fd)
- websocket.close(fd)
- end
- -- 注册接收skynet协议列表
- skynet.register_protocol {
- name = "client",
- id = skynet.PTYPE_CLIENT
- }
- skynet.start(
- function()
- skynet.dispatch(
- "lua",
- function(session, source, cmd, ...)
- local f = root[cmd]
- if not f then
- skynet.error("wsGate can't dispatch cmd " .. (cmd or nil))
- return
- end
- if session == 0 then
- f(source, ...)
- else
- skynet.ret(skynet.pack(f(source, ...)))
- end
- end
- )
- skynet.register(".ws_gate")
- end
- )
|