HomeServer/Server/Lib/Http/WebSocket.lua
2024-11-20 15:41:37 +08:00

178 lines
6.4 KiB
Lua

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