local skynet = require "skynet" local socket = require "skynet.socket" local service = require "skynet.service" require "skynet.manager" local websocket = require "http.websocket" local log = require "Log" local dataType = require "DataType" local errorInfo = require "ErrorInfo" local MaxBuffSize = 409600 --200K local handle = {} local MODE, agentId = ... if MODE == "agent" then function handle.connect(id) print("ws connect from: " .. tostring(id)) end function handle.handshake(id, header, url) local addr = websocket.addrinfo(id) print("ws handshake from: " .. tostring(id), "url", url, "addr:", addr) print("----header-----") for k,v in pairs(header) do print(k,v) end print("--------------") end function handle.message( sokcketId , msg, msg_type) assert(msg_type == "binary" or msg_type == "text") if "binary" == msg_type then local packetSize = string.sub( msg , 1, 8 ) --获取8位头数据 if not packetSize then websocket.close( socket) log.info(string.format("ws客户端主动关闭连接 SocketId %d ", sokcketId )) return end packetSize = tonumber(packetSize) if not packetSize then websocket.close( socket) log.info(string.format("ws客户端主动关闭连接 SocketId %d ", sokcketId )) return end if packetSize > MaxBuffSize or packetSize <= 0 then websocket.close( socket) log.info(string.format("ws关闭连接 SocketId %d 数据量超过阀值 最大值 %d 或者小于等于0 当前包大小 %d", sokcketId , MaxBuffSize , packetSize)) return end local c2sData = {} local s2cData = {} c2sData.netType = dataType.NetType_WebSocket c2sData.socketId = sokcketId c2sData.agentId = tonumber(agentId) --获取IP地址 local addr = websocket.addrinfo( sokcketId ) local pos = string.find(addr,":") addr = string.sub(addr,1,pos - 1) c2sData.addr = addr c2sData.isConnect = true c2sData.data= string.sub( msg ,9, packetSize + 8 ) if not c2sData.data then websocket.close( socket) log.info(string.format("ws关闭连接 SocketId %d 包数据为空,可能客户端关闭连接", sokcketId)) return end --把消息转发到对应的地方处理 local s2cData,retLen = skynet.call("StartServer", "lua","TcpMsg",c2sData ) if s2cData then retLen = string.format("%08d",string.len(s2cData)) websocket.write(sokcketId, retLen..s2cData , msg_type) end else websocket.write(sokcketId, msg , msg_type) end end function handle.ping(id) --log.info("ws ping from: " .. tostring(id) .. "\n") end function handle.pong(id) --log.info("ws pong from: " .. tostring(id)) end function handle.close(id, code, reason) log.info("server disconnect ws close from: " .. tostring(id), code, reason) --告诉上层,该玩家已经断线了 local c2sData = {} c2sData.netType = dataType.NetType_WebSocket c2sData.socketId = id c2sData.isConnect = false skynet.call("StartServer", "lua","TcpMsg",c2sData) end function handle.error(id) log.info("client disconnect or nginx disconnect ws error from: " .. tostring(id)) --告诉上层,该玩家已经断线了 local c2sData = {} c2sData.netType = dataType.NetType_WebSocket c2sData.socketId = id c2sData.isConnect = false skynet.call("StartServer", "lua","TcpMsg",c2sData) end skynet.start(function () skynet.dispatch("lua", function (_,_, sokcketId, protocol, addr) if "WebSocketAgentData" == protocol then --发送数据到客户端 local retLen = string.format("%08d",string.len(addr)) local isSuc = websocket.write( sokcketId , retLen..addr , "binary" ) elseif "WebSocketAgentClose" == protocol then --关闭连接 websocket.close( sokcketId ) else local ok, err = websocket.accept(sokcketId, handle, protocol, addr) if not ok then log.info(err) end end end) end) else local serverIp , serverPort = ... skynet.start(function() local agent = {} for i= 1, 20 do agent[i] = skynet.newservice(SERVICE_NAME, "agent" , i ) end local balance = 1 local protocol = "ws" local id = socket.listen(serverIp, serverPort) skynet.error(string.format("Listen websocket port 9948 protocol:%s", protocol)) socket.start(id, function(id, addr) print(string.format("accept client socket_id: %s addr:%s", id, addr)) skynet.send(agent[balance], "lua", id, protocol, addr) balance = balance + 1 if balance > #agent then balance = 1 end end) skynet.register("WebSocketAgent") skynet.dispatch("lua", function (_,_, cmd, ...) local socketId , agentId , c2sData = ... local isDo,s2cData = false,{} function Do( c2sData ) s2cData.code = errorInfo.Suc if "KickUserOffline" == cmd then skynet.send(agent[ agentId ], "lua", socketId, "WebSocketAgentClose", c2sData) else --服务器向客户端发送的消息 skynet.send(agent[ agentId ], "lua", socketId, "WebSocketAgentData", c2sData) end return s2cData end isDo,s2cData = pcall( Do, c2sData ) local sendMsg,sendLen = 0,0 if isDo then sendMsg,sendLen = skynet.pack(s2cData) else print("WebSocket 内部错误信息",s2cData) s2cData ={} s2cData.code = errorInfo.ErrorCode.InnerError sendMsg,sendLen = skynet.pack(s2cData) end --返回去 skynet.ret(sendMsg,sendLen) end) end) end