HomeServer/lualib-src/Server-main/AllServer/RouteServer/RouteServer.lua
2024-11-20 15:41:37 +08:00

291 lines
11 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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