HomeServer/Server/Start.lua

440 lines
13 KiB
Lua
Raw Permalink Normal View History

2024-11-20 15:41:09 +08:00
local skynet = require "skynet"
require "skynet.manager"
skynet.server = {}
require "Include"
local json =require "json"
local gameCmd = require "GameCmd"
local log = require "Log"
local errorInfo = require "ErrorInfo"
local cluster = require "skynet.cluster"
local socket = require "skynet.socket"
local pb = require "pb"
local mongo = require "skynet.db.mongo"
local redis = require "skynet.db.redis"
local redisKeyUrl = require "RedisKeyUrl"
local serverId = tonumber(skynet.getenv "serverId")
local clusterServer = require "ClusterServer"
local db = require "DB"
--AES 04169967a0dda41831aae37ae5f7c37a
--接收HTTP消息
function skynet.StartRecv()
skynet.register("StartServer")
skynet.dispatch("lua", function (_,_, cmd, ...)
if "TcpMsg" == cmd then --Tcp消息
local c2sData = ...
local isDo,s2cData = false,nil
s2cData = skynet.server.tcpServer:TcpRecv( c2sData )
local sendMsg,sendLen = skynet.pack(s2cData)
skynet.ret(sendMsg,sendLen)
elseif "HttpMsg" == cmd then --Http消息
local id ,url , c2sData , addr ,header= ...
--对接收到消息进行处理
local isDo,s2cData = false,nil
function Do(url ,c2sData , addr)
--获取IP地址
local pos = string.find(addr,":")
addr = string.sub(addr,1,pos - 1)
local bodyStr=c2sData
c2sData = json:decode(c2sData)
if c2sData ~=nil and bodyStr ~= nil then
c2sData.bodyStr=bodyStr
end
s2cData = skynet.server.httpServer:Recv(url, c2sData , addr , header)
return s2cData
end
--pcall调用一下有异常直接返回
isDo,s2cData = pcall(Do,url ,c2sData , addr , header)
local sendMsg,sendLen = 0,0
if isDo then
sendMsg,sendLen = skynet.pack(s2cData)
else
log.info("StartServer HttpMsg内部错误信息",s2cData)
s2cData ={}
s2cData.code = errorInfo.ErrorCode.InnerError
s2cData = json:encode(s2cData)
sendMsg,sendLen = skynet.pack(s2cData)
end
--返回去
skynet.ret(sendMsg,sendLen)
elseif "ClusterMsg" == cmd then --集群消息
local sendMsg,sendLen = 0,0
sendMsg,sendLen = skynet.pack(clusterServer:ClusterRecv(...))
skynet.ret(sendMsg,sendLen)
--elseif "RedisMsg" == cmd then --Redis消息 (废弃,后面再清理)
-- skynet.server.gameServer:RedisMsgRecv(...)
end
end)
end
--初始化各种模块
function skynet.Init()
skynet.newservice("Logger")
local isOk = true
--载入游戏需要的配置文件
skynet.server.gameConfig:LoadConfig()
skynet.server.gameConfig:LoadJson()
skynet.server.gameConfig:LoadProto()
skynet.desKey = "12345678"
skynet.AddTime = 0
skynet.ServerName = clusterServer:GetServerTypeName( serverId )
--初始化Redis
skynet.InitRedis()
--游戏服可以连接多个数据库
skynet.InitDB( false )
--初始化MongoDB
skynet.InitMongoDB()
--先初始化clusterServer ,再初始其它模块
skynet.server.clusterServer:Init()
if skynet.server.clusterServer:IsGameServer( serverId ) then
--游戏服才会用到该模块
skynet.server.redisCache:Init()
end
for key, value in pairs(skynet.server) do
if not string.find(key, "redis") and not string.find(key, "mongo") and "clusterServer" ~= key and value.Init then
value:Init()
end
end
log.info("程序模块初始化完成")
--获取当前服务器IP信息
local cfgServer = skynet.server.common:GetClusterConfig( serverId )
if not cfgServer then
log.info("当前获取集群配置出错1 ",serverId)
return false
end
log.info("获取当前服务器配置完成")
--http底层加载
if "" ~= cfgServer.httpPort then
if skynet.server.clusterServer.multiServerID == serverId then
--多功能服需要传输大数据单独修改一下最大传输数量为1M
skynet.server.httpSocket = skynet.newservice("HttpMultiSocket", "0.0.0.0" , cfgServer.httpPort)
else
skynet.server.httpSocket = skynet.newservice("HttpSocket", "0.0.0.0" , cfgServer.httpPort)
end
end
log.info("Http模块初始化完成")
--登陆服和游戏服不绑定TCP端口
if "" ~= cfgServer.tcpPort then
skynet.server.tcpSocket = skynet.newservice("TcpSocket", "0.0.0.0" , cfgServer.tcpPort)
end
log.info("Tcp模块初始化完成")
if "" ~= cfgServer.webSocketPort then
skynet.server.webSocket = skynet.newservice("WebSocket", "0.0.0.0" , cfgServer.webSocketPort)
end
log.info("WebSocket模块初始化完成")
--通过配置获取的节点进行组装
local clusterList = {}
local serverName = ""
for k, v in pairs(skynet.server.gameConfig.ClusterServerConfig) do
if serverId == v.serverId then
skynet.externalIp = v.externalIp
end
serverName = clusterServer:GetServerTypeClusterName( v.serverId )
clusterList[ serverName ] = string.format("%s:%s",v.internalIp ,v.clusterPort)
end
--载入集群
local clusterName = clusterServer:GetServerTypeClusterName( serverId )
cluster.reload(clusterList)
cluster.register(clusterName)
cluster.open(clusterName)
skynet.server.cluster = cluster
log.info("载入集群节点配置完成")
end
--主服务器
skynet.start(function()
skynet.StartRecv()
skynet.Init()
skynet.fork(skynet.ClusterTimer,500)
skynet.fork(skynet.GameTimer,500)
skynet.fork(skynet.GameTimer5Minute,100*60*5)--五分钟定时任务
skynet.fork(skynet.SaveMongoDBTimer,500) --500
skynet.fork(skynet.SaveMysqlDBTimer,500) --500
skynet.fork(skynet.SyncTimer,500) --500
--skynet.fork(skynet.Subscribe)(废弃,后面再清理)
log.info("服务器成功开启")
end)
--初始化Redis
function skynet.InitRedis()
--redis连接
local redisCfg =
{
host = skynet.server.gameConfig.RedisConfig.host ,
port = skynet.server.gameConfig.RedisConfig.port ,
db = skynet.server.gameConfig.RedisConfig.dbIndex,
auth = skynet.server.gameConfig.RedisConfig.password
}
skynet.server.redis = redis.connect(redisCfg)
if not skynet.server.redis then
log.info("连接Redis数据库失败")
return false
else
log.info(string.format("Redis 数据库连接成功 信息 IP地址 %s 端口 %s" ,redisCfg.host , redisCfg.port))
end
--RedisUser连接目前数量为2根据配置文件来确定
for i = 1, 2, 1 do
local tmpConfig = skynet.server.gameConfig[ "RedisUser"..i.."Config" ]
if tmpConfig then
local redisUserCfg = { host = tmpConfig.host , port = tmpConfig.port , db = tmpConfig.dbIndex , auth = tmpConfig.password }
skynet.server[ "redisUser"..i ] = redis.connect( redisUserCfg )
if not skynet.server[ "redisUser"..i ] then
log.info("连接RedisUser数据库失败",i)
return false
else
log.info(string.format("RedisUser%d 数据库连接成功 信息 IP地址 %s 端口 %s" , i , redisUserCfg.host , redisUserCfg.port))
end
end
end
end
--初始化DB
function skynet.InitDB( isReConnect )
local isOk = true
local dbConfig = skynet.server.gameConfig.DBInfoConfig
local cfgOneServer = skynet.server.gameConfig:GetCurClusterServerCfg( serverId )
--分析要连接的数据库名
if "" ~= cfgOneServer.dbName then
local dbNameList = skynet.server.common:Split( cfgOneServer.dbName , "|")
for k, dbName in pairs( dbNameList ) do
if isReConnect then
skynet.server.db:DisConnect( dbName )
skynet.sleep(10) --间隔10毫秒
end
isOk = skynet.server.db:Connect( dbConfig.host ,dbConfig.port ,dbConfig.user,dbConfig.password , dbName )
if not isOk then
return false
end
end
end
end
--初始化MongoDB
function skynet.InitMongoDB()
if skynet.server.gameConfig:IsMongoDB() then
local dbCfg =
{
host = skynet.server.gameConfig.MongDBConfig.host ,
port =skynet.server.gameConfig.MongDBConfig.port ,
username = skynet.server.gameConfig.MongDBConfig.username,
password = skynet.server.gameConfig.MongDBConfig.password,
--authdb = skynet.server.gameConfig.MongDBConfig.authdb
}
local authdb = skynet.server.gameConfig.MongDBConfig.authdb
skynet.server.mongo = mongo.client(dbCfg)[ authdb ]
--skynet.server.mongo.user1:safe_insert({_id = 1, name = "user2", password = "123456"}, true)
--skynet.server.mongo.user1:findOne({test_key = 1});
--skynet.server.mongo.user1:safe_update({ _id = 3} ,{name = "user3.2", password = "123456"} , true )
--local curData = skynet.server..mongo.user3:findOne()
log.info(string.format("MongoDB数据库连接成功 信息 IP地址 %s 端口 %s" , dbCfg.host , dbCfg.port))
end
end
--集群Timer
function skynet.ClusterTimer( timeStamp )
local isSuc ,err = nil,nil
local todayTime = skynet.GetTime()
while true do
--跨天
if not skynet.server.common:IsSameDay(skynet.GetTime() , todayTime ) then
log.info(string.format("集群Timer 服务器跨天 当前时间 %d 服务器记录时间 %d",skynet.GetTime() ,todayTime ))
--跨天TIMER
function Do()
skynet.server.clusterServer:OnNewDay()
end
isSuc,err = pcall(Do)
if not isSuc then
log.info("集群Timer 跨天有报错",err)
end
todayTime = skynet.GetTime()
end
--5秒TIMER
function Do()
skynet.server.clusterServer:On5SecTimer()
end
isSuc,err = pcall(Do)
if not isSuc then
log.info("集群Timer 5秒有报错",err)
end
skynet.sleep(timeStamp)
end
end
--游戏TImer主要是游戏逻辑
function skynet.GameTimer( timeStamp )
local isSuc ,err = nil,nil
local todayTime = skynet.GetTime()
while true do
--跨天
if not skynet.server.common:IsSameDay(skynet.GetTime() , todayTime ) then
local str = string.format("游戏TImer 服务器跨天 当前时间 %d 服务器记录时间 %d",skynet.GetTime() , todayTime )
log.info(str)
--跨天TIMER
--clusterServer:OnNewDay()
for key, value in pairs(skynet.server) do
if "table"== type(value) and value.OnNewDay and not string.find(key, "redis") and not string.find(key, "mongo") and
"clusterServer" ~= key and "accountCenter" ~= key and "timer" ~= key then
function Do(value)
value:OnNewDay()
end
isSuc,err = pcall(Do,value)
if not isSuc then
log.info("游戏TImer 跨天TIMER有报错",key,err)
end
end
end
todayTime = skynet.GetTime()
end
--5秒TIMER
for key, value in pairs(skynet.server) do
if "table" == type(value) and value.On5SecTimer and not string.find(key, "redis") and not string.find(key, "mongo") and
"clusterServer" ~= key and "accountCenter" ~= key and "timer" ~= key then
function Do(value)
local t1 = skynet.GetTime()
value:On5SecTimer()
local t2 = skynet.GetTime() - t1
if t2 > 1 then
skynet.server.clusterServer:SendErrorInfoToCenter( nil , errorInfo.ErrorCode.CalcTimeTooLong , string.format("%s 计算时间过长", key))
log.info("游戏Timer 运行时间",key, t2 )
end
end
isSuc,err = pcall(Do,value)
if not isSuc then
log.info("游戏TImer 5秒TIMER有报错",key,err)
end
end
end
skynet.sleep(timeStamp)
end
end
--游戏TImer主要是游戏逻辑-五分钟
function skynet.GameTimer5Minute( timeStamp )
local isSuc ,err = nil,nil
while true do
--五分钟秒TIMER
for key, value in pairs(skynet.server) do
if "table" == type(value) and value.On5MinTimer and not string.find(key, "redis") and not string.find(key, "mongo") and
"clusterServer" ~= key and "accountCenter" ~= key and "timer" ~= key then
function Do(value)
local t1 = skynet.GetTime()
value:On5MinTimer()
local t2 = skynet.GetTime() - t1
if t2 > 1 then
skynet.server.clusterServer:SendErrorInfoToCenter( nil , errorInfo.ErrorCode.CalcTimeTooLong , string.format("%s 计算时间过长", key))
log.info("游戏Timer 运行时间",key, t2 )
end
end
isSuc,err = pcall(Do,value)
if not isSuc then
log.info("游戏TImer 5分钟TIMER有报错",key,err)
end
end
end
skynet.sleep(timeStamp)
end
end
--保存Mongo数据库Timer
function skynet.SaveMongoDBTimer( timeStamp )
--只有游戏服并且配置了Mongo数据库才开启timer
if skynet.server.gameConfig:IsMongoDB() and serverId >= clusterServer.gameServerMinID and serverId <= clusterServer.gameServerMaxID then
log.info("开启Mongo数据库Timer")
while true do
skynet.server.accountCenter:CheckSaveMongoDB()
skynet.sleep(timeStamp)
end
end
end
--保存Mysql数据库Timer
function skynet.SaveMysqlDBTimer( timeStamp )
if serverId >= clusterServer.gameServerMinID and serverId <= clusterServer.gameServerMaxID then
log.info("开启Mysql数据库Timer")
while true do
skynet.server.accountCenter:CheckSaveMysqlDB()
skynet.sleep(timeStamp)
end
end
end
--同步redis数据TImer
function skynet.SyncTimer( timeStamp )
while true do
skynet.server.timer:Refresh()
skynet.sleep(timeStamp)
end
end
--订阅Redis信息(废弃,后面再清理)
function skynet.Subscribe()
if not skynet.server.clusterServer:IsGameServer(serverId) then
return
end
--游戏服才发布-订阅功能
local redisCfg =
{
host = skynet.server.gameConfig.RedisConfig.host ,
port = skynet.server.gameConfig.RedisConfig.port ,
db = skynet.server.gameConfig.RedisConfig.dbIndex,
auth = skynet.server.gameConfig.RedisConfig.password
}
local w = redis.watch(redisCfg)
w:subscribe("mail") --订阅邮件
while true do
function Do()
local msg,channel = w:message()
skynet.send("StartServer", "lua","RedisMsg", msg , channel )
skynet.sleep(10)
return true
end
local isSuc,err = pcall(Do)
if not isSuc then
log.info("订阅Redis信息Timer 有报错",err)
end
end
end
--获取时间
function skynet.GetTime()
return os.time() + skynet.AddTime
end