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