NetBase = class("NetBase"); NetClientState = { Disconnect = 0, Connectting = 1, Connected = 2, } local function gettable(tab , key , defaultValue) local value = tab[key]; if value then return value else value = defaultValue tab[key] = value return value end end local function NetworkFuncGet(self , moduleID) return gettable(self, moduleID, { get = function(self , cmdID) return gettable(self, cmdID, { funcs = {}, callbacks = {}, dirty = true, insert = function(self , func) self.funcs[func] = 1 self.dirty = true end, remove = function(self , func) self.funcs[func] = nil self.dirty = true end, }) end, }) end -- 构造函数 function NetBase:ctor() -- 保存(模块->命令->函数)的对应关系 self.mNetworkFunc = {} -- 保存(函数->模块、命令)的对应关系 self.mFuncToCmd = {} self.mNetworkFunc.get = NetworkFuncGet -- 初始状态下是不需要重连的 -- 第一次成功链接后才设置为需要重连 -- 再往后可以根据需要修改 self.isNeedReconnect = false -- 游戏切换到后台之后缓存的服务器消息, -- 切换回来之后手动发送一遍 self.isBackGround = false; self.netMessageStack = {} app:addEventListener("applicationDidEnterBackground", handler(self,self.onApplicationDidEnterBackground)) app:addEventListener("applicationWillEnterForeground", handler(self, self.onApplicationWillEnterForeground)) end -- 需重写:连接时的回调 function NetBase:OnConnecttingCallback() end -- 需重写:连接成功之后的回调 function NetBase:OnConnectedCallback() end -- 需重写:断开连接时的回调 function NetBase:OnDisconnectCallback() end -- 是否处于链接状态 function NetBase:isConnected() if self.Socket then return self.Socket:state() == NetClientState.Connected; else return false end end -- function NetBase:isInited() return self.Socket ~= nil; end function NetBase:onRecvServerMsg(moduleID , cmdID , statusCode , stream) end -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------- -- 注册一个网络消息回调 function NetBase:regMsg(moduleID , cmdID , func) if type(func) ~= "function" then error("regMsg时传入了不正确的function,moduleID[" .. tostring(moduleID) .. "] cmdID[" .. tostring(cmdID) .. "] func[" .. tostring(func) .. "]"); return end self.mNetworkFunc:get(moduleID):get(cmdID):insert(func); self.mFuncToCmd[func] = {moduleID,cmdID}; end -- 反注册一个网络消息 function NetBase:unregMsg(func) if type(func) ~= "function" then error("unregMsg时传进来的第一个参数不是function"); end local funcToCmd = self.mFuncToCmd[func]; if funcToCmd == nil then return end self.mNetworkFunc:get(funcToCmd[1]):get(funcToCmd[2]):remove(func); self.mFuncToCmd[func] = nil; end -- 通过命令ID移除网络消息监听 function NetBase:removeMsgHandler(cmdID) for func,funcToCmd in pairs(self.mFuncToCmd) do if funcToCmd[2]==cmdID then self:unregMsg(func) end end end -- 发送消息到服务器 function NetBase:send(moduleID , cmdID , stream) print(string.format("发送消息:moduleID[%d] cmdID[%#x] size[%d]", moduleID, cmdID, NetStream.getWriteSize(stream))); -- 如果网络已经断开,则果断提示错误 if self.Socket:state() ~= NetClientState.Connected then --NetStream.delete(stream) showTooltip("网络已断开"); return; end self.Socket:send(moduleID , cmdID , stream) end -- 发送一个命令(不带用户数据)到服务器 function NetBase:sendCmd(moduleID , cmdID) local stream = NetStream.new(); self:send(moduleID , cmdID , stream); NetStream.delete(stream) end -- 网络消息处理函数 function NetBase:onNetworkMsg(moduleID , cmdID , statusCode , stream) if statusCode ~= 0 then --showTooltip("statusCode = "..statusCode); print(string.format("接受消息:moduleID[%d] cmdID[%#x] statusCode[%d]", moduleID, cmdID, statusCode)); else print(string.format("接受消息:moduleID[%d] cmdID[%#x] statusCode[%d] size[%d]", moduleID, cmdID, statusCode, NetStream.getReadSize(stream))); end local mod = self.mNetworkFunc[moduleID]; if mod then local cmd = mod[cmdID]; if cmd then if cmd.dirty then cmd.dirty = false cmd.callbacks = {} for i,v in pairs(cmd.funcs) do cmd.callbacks[i] = v end end local funcs = cmd.callbacks for func,v in pairs(funcs) do NetStream.reset(stream); func(statusCode , stream); end if cmd.dirty then cmd.callbacks = {} end end end end -- 开始连接 function NetBase:connect(ip, port) log("moduleID[99] - NetBase:connect() ") if self.Socket and self.Socket:state() == NetClientState.Connectting then --showTooltip("moduleID[99] - is Connectting, return") return; end -- 处理 socket 状态变化 local function onState(state) log("NetBase::connect() onState() state = ", tostring(state)) if state == NetClientState.Connectting then log("moduleID[99] - Connectting") self:OnConnecttingCallback() elseif state == NetClientState.Connected then log("moduleID[99] - Connected") -- self:closeTimer(); app.waitDialogManager:closeWaitNetworkDialog() self:OnConnectedCallback() elseif state == NetClientState.Disconnect then log("moduleID[99] - Disconnect") -- self:closeTimer(); app.waitDialogManager:closeWaitNetworkDialog() self:OnDisconnectCallback() end end -- 处理服务器消息 local function onMessage(moduleID , cmdID , statusCode , stream) -- 如果游戏退入后台,则拦截所有除心跳之外的消息 -- 回来的时候再轮流处理 if self.isPause and cmdID ~= 0x2008 then local streamData = NetStream.getReadData(stream); local newStream = NetStream.new(streamData); table.insert(self.netMessageStack, {moduleID=moduleID, cmdID=cmdID , statusCode=statusCode , stream=newStream}) else self:onNetworkMsg(moduleID , cmdID , statusCode , stream) self:onRecvServerMsg(moduleID , cmdID , statusCode , stream) end end if not self.Socket then self.Socket = NetClient.new(onMessage , onState); -- 网宿水印 local setting = require("luaScript.Config.Setting") if setting and setting.NetClientParams then local v = setting.NetClientParams local num = #setting.NetClientParams if num == 5 then self.Socket:setParams(v[1], v[2], v[3], v[4], v[5]) end end local timeOut = 5; if isIOSReviewVersion() then timeOut = 30; end if self.Socket.setConnectTimeout then self.Socket:setConnectTimeout(timeOut) end if self.Socket.setWriteTimeout then self.Socket:setWriteTimeout(timeOut) end if self.Socket.setReadTimeout then self.Socket:setReadTimeout(timeOut) end end -- 记录当前使用的ip和端口 self.ip = ip; self.port = port; if not ip or not port then showTooltip("无效的 ip 或 port"); return; end -- 连接网络 app.waitDialogManager:showWaitNetworkDialog("登录中....") -- self:startTimer(); if isDebug() then showTooltip("尝试链接 "..ip.." : "..port) end log("尝试链接 "..ip.." : "..port) self.netMessageStack = {} getHostAndIpByUrl(ip, function(host2, ip2) if ip2 then self.Socket:connect(ip2, port) else self.Socket:connect(ip, port) end end) end -- 断开连接 function NetBase:close() log("200000 moduleID[99] NetBase:close()") if self.Socket then self.Socket:close(); end end -- 开始连接后启动计时器,指定的时间没有连接上,记为超时 function NetBase:startTimer() log("moduleID[99] NetBase:startTimer()"); local function outTimeCallback() log("moduleID[99] NetBase:startTimer() outTimeCallback()"); self:close() end -- 先关闭,再创建 self:closeTimer() local timeOut = getNetTimeOutNum(); log("moduleID[99] NetBase:startTimer() timeOut = ", tostring(timeOut)); self.scheduleHandle = cc.Director:getInstance():getScheduler():scheduleScriptFunc(outTimeCallback, timeOut, false); log("moduleID[99] NetBase:startTimer() scheduleHandle = ", tostring(self.scheduleHandle)); end function NetBase:closeTimer() log("moduleID[99] NetBase:closeTimer()"); if self.scheduleHandle then log("moduleID[99] NetBase:closeTimer() unscheduleScriptEntry ", tostring(self.scheduleHandle)); cc.Director:getInstance():getScheduler():unscheduleScriptEntry(self.scheduleHandle); self.scheduleHandle = nil; else log("moduleID[99] NetBase:closeTimer() scheduleHandle is nil"); end end function NetBase:onApplicationDidEnterBackground() self:onMsgPause() end function NetBase:onApplicationWillEnterForeground() self:onMsgResume(); end function NetBase:onMsgPause() log("moduleID[99] NetBase:onMsgPause") self.isPause = true end function NetBase:onMsgResume() log("moduleID[99] NetBase:onMsgResume") if self.netMessageStack and #self.netMessageStack > 0 then app:dispatchEvent({name = "onDealMessageStackBegin" , net = self}); for k,v in ipairs(self.netMessageStack) do self:onNetworkMsg(v.moduleID , v.cmdID, v.statusCode , v.stream) self:onRecvServerMsg(v.moduleID , v.cmdID, v.statusCode , v.stream) NetStream.delete(v.stream); end app:dispatchEvent({name = "onDealMessageStackEnd" , net = self}); end self:onMsgClear(); self.isPause = false end function NetBase:onMsgResumeEx() self.isPause=false while #self.netMessageStack > 0 do if self.isPause then return end self:runNextMsg() end end function NetBase:runNextMsg() log("NetBase:runNextMsg") if self.netMessageStack and #self.netMessageStack > 0 then local v = self.netMessageStack[1] table.remove(self.netMessageStack,1) self:onNetworkMsg(v.moduleID , v.cmdID, v.statusCode , v.stream) self:onRecvServerMsg(v.moduleID , v.cmdID, v.statusCode , v.stream) NetStream.delete(v.stream) return true end return false end function NetBase:onMsgClear() self.netMessageStack = {} end return NetBase;