HomeServer/lualib-src/Server-main/AllServer/RouteServer/RouteServer.lua

291 lines
11 KiB
Lua
Raw Permalink Normal View History

2024-11-20 15:41:09 +08:00
local skynet = require "skynet"
local oo = require "Class"
local gameCmd = require "GameCmd"
local json =require "json"
local log = require "Log"
local sqlUrl = require "SqlUrl"
local defense = require "Defense"
local playerFields = require "PlayerFields"
local errorInfo = require "ErrorInfo"
local serverId = tonumber(skynet.getenv "serverId")
local clusterServer = require "ClusterServer"
local redisKeyUrl = require "RedisKeyUrl"
local RouteServer = oo.class(clusterServer)
--初始化
function RouteServer:Init()
--self.serverInfo = {} --服务器当前信息
self.platformType = {}
self.platformType["Apple"] = true
self.platformType["Android"] = true
self.serverInfo.isStopServer = false --是否停止服务器
self.serverInfo.isCanUserEnter = true --用户是否能进入
self.serverInfo.maxPlayerCountPerGS = 20000 --每个游戏服最大人数
self.serverInfo.tokenBucketCurCount = 200 --令牌漏桶当前数量
self.serverInfo.tokenBucketAddCount = 30 --令牌漏桶每5秒新增数量
self.serverInfo.tokenBucketMaxCount = 300 --令牌漏桶最大数量
self.lastQueryGameServerInfoTime = skynet.GetTime() --上一次查询大厅服时间
end
--跨天
function RouteServer:OnNewDay()
if not self:IsRouteServer( serverId ) then
return
end
end
--1秒Timer
function RouteServer:On1SecTimer()
if not self:IsRouteServer( serverId ) then
return
end
end
--5秒Timer
function RouteServer:On5SecTimer()
if not self:IsRouteServer( serverId ) then
return
end
--每5秒新增令牌桶的数量
self.serverInfo.tokenBucketCurCount = self.serverInfo.tokenBucketCurCount + self.serverInfo.tokenBucketAddCount
if self.serverInfo.tokenBucketCurCount > self.serverInfo.tokenBucketMaxCount then
self.serverInfo.tokenBucketCurCount = self.serverInfo.tokenBucketMaxCount
end
end
--接收集群数据
function RouteServer:ClusterRecv(...)
local cmd , c2sData = ...
local s2sData = {}
s2sData.code = errorInfo.Suc
if self.Center2All_ServerManageCmd == cmd then
elseif self.Center2All_SyncClusterInfo == cmd then
self:RecvSyncClusterInfo( c2sData )
elseif self.Center2All_SyncServerConfig == cmd then --同步服务器配置
self:RecvSyncServerConfig( c2sData )
else
log.info(string.format("集群服务器 消息接口 %d 不存在", cmd))
s2sData.code = errorInfo.ErrorCode.NoExistInterface
end
log.info(string.format("集群服 执行命令 %d 返回消息状态 %d " , cmd , s2sData.code))
return s2sData
end
--接收HTTP数据
function RouteServer:HttpRecv( c2sData , url , addr )
local s2cData = {}
s2cData.code = errorInfo.Suc
c2sData.addr = addr
--禁止进入
if not self.serverInfo.isCanUserEnter then
s2cData.code = errorInfo.ErrorCode.ForbidUserLogin
return s2cData
end
--令牌桶数量不足
if 0 == self.serverInfo.tokenBucketCurCount then
s2cData.code = errorInfo.ErrorCode.TokenCountNotEnough
return s2cData
end
if "GetGateUrl" == url then
self:GetGateUrl( c2sData , s2cData )
elseif "SetConfig" == url then
self:SetConfig( c2sData , s2cData )
elseif "health" == url then
self:Health( c2sData , s2cData )
else
log.info(string.format("Http服务器 消息接口 %s 不存在", url))
s2cData.code = errorInfo.ErrorCode.NoExistInterface
end
log.info("Http服务器 消息接口 ",url ,"返回信息",s2cData.code)
return s2cData
end
--获取网关地址
function RouteServer:GetGateUrl( c2sData , s2cData )
--验证登陆接口参数
if nil == c2sData or nil == c2sData.platform or nil == c2sData.loginAccount then
s2cData.code = errorInfo.ErrorCode.ErrRequestParam
return s2cData
end
--检查平台合法性
--[[
if not self.platformType[c2sData.platform] then
s2cData.code = errorInfo.ErrorCode.NoExistPlatformType
return s2cData
end
]]
--是否停止维护
if self.serverInfo.isStopServer then
s2cData.code = errorInfo.ErrorCode.StopServer
return s2cData
end
log.info(string.format("平台 %s 玩家 %s 开始查找玩家", c2sData.platform , c2sData.loginAccount ))
self:IsVerifyValid( c2sData , s2cData )
--令牌数量减1
self.serverInfo.tokenBucketCurCount = self.serverInfo.tokenBucketCurCount - 1
local gameServerId = nil
--向每个在线的网关进行询问用户是否在线,不在线就找人数最少的网关
local clusterReturn = {}
local isExistPlayer = nil
for k, v in pairs(self.clusterInfo) do
--不管游戏服是运行还是停止状态,只要该玩家在里面,就能让该玩家继续登陆这台游戏服
if self:IsGameServer( v.serverId ) and v.status == self.Status_Running or v.status == self.Status_Stop then
clusterReturn = self:CallMsgToServer(v.serverId , self.Route2Game_QueryUserOnline , c2sData )
if errorInfo.Suc == clusterReturn.code and clusterReturn.isExistPlayer then
gameServerId = v.serverId
log.info(string.format("平台 %s 玩家 %s 已经在游戏服 %d", c2sData.platform , c2sData.loginAccount , gameServerId ))
break
end
--[[
--从redis中检查各个游戏服中有不有该玩家
local redisKey = string.format(redisKeyUrl.AccountServerOnlinePlayerList , c2sData.platform , v.serverId )
isExistPlayer = skynet.server.redis:sismember( redisKey , c2sData.loginAccount )
if isExistPlayer then
gameServerId = v.serverId
log.info(string.format("平台 %s 玩家 %s 已经在游戏服 %d", c2sData.platform , c2sData.loginAccount , v.serverId ))
break
end
]]
end
end
--优先给需要玩家的游戏服,好做压力测试
if not gameServerId then
for k, v in pairs(self.clusterInfo) do
if self:IsGameServer( k ) and v.status == self.Status_Running then
local curCount = v.serverInfo.playerCount.offline + v.serverInfo.playerCount.playing
if 0 ~= v.serverInfo.needPlayerCount and curCount < v.serverInfo.needPlayerCount then
gameServerId = v.serverId
break
end
end
end
end
--寻找人数最少的网关
if not gameServerId then
local minOnlineCount = -1
local curCount = 0
for k, v in pairs(self.clusterInfo) do
--分配玩家到运行状态的游戏服
if self:IsGameServer( k ) and v.status == self.Status_Running then
curCount = v.serverInfo.playerCount.offline + v.serverInfo.playerCount.playing
if ( -1 == minOnlineCount or curCount < minOnlineCount ) and curCount <= self.serverInfo.maxPlayerCountPerGS then
gameServerId = v.serverId
minOnlineCount = curCount
end
end
end
end
if not gameServerId or not self.clusterInfo[ gameServerId ] then
log.info("未找到该游戏服信息" , gameServerId)
s2cData.code = errorInfo.ErrorCode.GetGateUrlFailed
return
end
log.info(string.format("玩家 %s 获得游戏服登陆许可 %d",c2sData.loginAccount , gameServerId))
--同步Token到指定的大厅服
local loginToken = skynet.server.common:RandToken()
local cfgServer = nil
for k, v in pairs( skynet.server.gameConfig.ClusterServerConfig ) do
if gameServerId == v.serverId then
cfgServer = v
break
end
end
if not cfgServer then
log.info("未加找相关服的配置" , gameServerId)
s2cData.code = errorInfo.ErrorCode.GetGateUrlFailed
return
end
--向指定的游戏服发送玩家token
s2cData.loginIP = cfgServer.externalIp
s2cData.loginPort = cfgServer.tcpPort
s2cData.loginToken = loginToken
self:SendTokenToGameServer( gameServerId , c2sData.platform ,c2sData.loginAccount , loginToken )
return
end
--设置配置
function RouteServer:SetConfig( c2sData , s2cData )
if nil == c2sData.key or nil == c2sData.value then
s2cData.code = errorInfo.ErrorCode.ErrRequestParam
log.info(string.format("错误的请求参数 key %s value %s" , c2sData.key , c2sData.value))
return
end
if nil == self.serverInfo[ c2sData.key ] then
s2cData.code = errorInfo.ErrorCode.ErrRequestParam
log.info(string.format("不存在的请求参数 key %s value %s" , c2sData.key , c2sData.value))
return
else
log.info(string.format("修改前参数 key %s value %s" , c2sData.key , self.serverInfo[ c2sData.key ] ))
self.serverInfo[ c2sData.key ] = c2sData.value
log.info(string.format("修改后参数 key %s value %s" , c2sData.key , self.serverInfo[ c2sData.key ] ))
end
end
--健康管理
function RouteServer:Health( c2sData , s2cData )
s2cData.code = 200
end
--发送登陆TOKEN到登陆服务器
function RouteServer:SendTokenToGameServer( serverId , platform , loginAccount , loginToken)
local clusterMsg = {}
clusterMsg.platform = platform
clusterMsg.loginAccount = loginAccount
clusterMsg.loginToken = loginToken
self:SendMsgToServer(serverId , self.Route2Game_UserLoginToken , clusterMsg)
end
--验证是否有效
function RouteServer:IsVerifyValid( c2sData , s2cData )
for k, v in pairs(self.clusterInfo) do
if self.monitorServerID == v.serverId and self.Status_Running == v.status then
--大厅服没有开,就不用网络服验证,直接通过
s2cData = self:CallMsgToServer( v.serverId , self.Route2Monitor_VerifyValid , c2sData)
if not s2cData then
s2cData.code = errorInfo.ErrorCode.NoExistServer
log.info(string.format("集群服serverId %d 不在线", serverId))
return false
else
local isBlack = false
if errorInfo.ErrorCode.BlackListAccount == s2cData.code then
log.info(string.format("路由服 平台 %s 帐号 %s 在帐号黑名单中" , c2sData.platform , c2sData.loginAccount))
isBlack = true
elseif errorInfo.ErrorCode.BlackListAddr == s2cData.code then
log.info(string.format("路由服 平台 %s 帐号 %s 在IP黑名单中" , c2sData.platform , c2sData.loginAccount))
isBlack = true
end
if isBlack then
return false
else
return true
end
end
end
end
return true
end
--如果是当前服务器ID那么就加入进来
if serverId >= clusterServer.routerServerMinID and serverId <= clusterServer.routerServerMaxID then
skynet.server.routeServer = RouteServer
end
return RouteServer