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

440 lines
13 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"
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