local Net = class("Net"); 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 Net:ctor() -- 保存模块->命令->函数的对应关系 self.mNetworkFunc = {} -- 保存函数->模块命令的对应关系 self.mFuncToCmd = {} self.mNetworkFunc.get = NetworkFuncGet self.logTag = "" -- 所有IP self.netConfigMap = {} -- 当前IP的索引 self.ipIndex = nil; -- 当前IP使用的次数 self.curReconnectTimes = 0; -- 每个IP最多重连3次 self.maxReconnectTimes = 3; self.OnState = function(state)end; -- 网络消息处理函数 local function 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 self.OnMessage = onNetworkMsg self.OnConnect = function() log(self.logTag.."net::OnConnect()") self.curReconnectTimes = 0; app:dispatchEvent({name = "onConnect" , net = self}); end self.OnConnectting = function() log(self.logTag.."net::OnConnectting()") app:dispatchEvent({name = "onConnectting" , net = self}); end self.OnDisconnect = function() log(self.logTag.."net::OnDisconnect()") app:dispatchEvent({name = "onDisconnect" , net = self}); end end -- 清空网络端口列表 function Net:clearIpList() -- 所有IP self.netConfigMap = {} -- 当前IP的索引 self.ipIndex = nil; -- 当前IP使用的次数 self.curReconnectTimes = 0; end -- 添加网络端口列表 function Net:addIp(ip, port) if not ip or not port then return end if not self.netConfigMap then self.netConfigMap = {} end table.insert(self.netConfigMap, {ip = ip, port = port}) end function Net:removeIp(index) local nSize = #self.netConfigMap if tonumber(index) <= tonumber(nSize) then table.remove(self.netConfigMap, tonumber(index)) end -- 可用的IP地址用完了,就重启游戏,重新拉取新配置 if #self.netConfigMap <= 0 then cc.Application:getInstance():restart(); return end end -- 从网络端口列表中获取一个可用的端口 function Net:getIp() if not self.netConfigMap or #self.netConfigMap <= 0 then return nil end self.ipIndex = math.random(#self.netConfigMap) self.curReconnectTimes = 0; local value = self.netConfigMap[self.ipIndex] return value.ip, value.port; end -- 注册一个网络消息回调 function Net: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 Net: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 Net:removeMsgHandler(cmdID) for func,funcToCmd in pairs(self.mFuncToCmd) do if funcToCmd[2]==cmdID then self:unregMsg(func) end end end -- 发送消息到服务器 function Net: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 local function run() local stream = NetStream.new(); self.OnMessage(moduleID , cmdID , -2 , stream); NetStream.delete(stream) end runInNextFrame(run); return; end self.Socket:send(moduleID , cmdID , stream) end -- 重新连接 function Net:reconnect() self:close(); self.OnConnectting() -- 从网络配置中随机连接 local ip, port if not self.ipIndex then ip, port = self:getIp() end if self.curReconnectTimes < self.maxReconnectTimes then local value = self.netConfigMap[self.ipIndex] if value then ip, port = value.ip, value.port; end print(string.format("%s Net:reconnect() use old ,ip = %s, port = %s",self.logTag, ip, port)) else -- 删除当前使用的ip self:removeIp(self.ipIndex) -- 重新获取新的ip ip, port = self:getIp() print(string.format("%s Net:reconnect() use new ,ip = %s, port = %s",self.logTag, ip, port)) end if not ip or not port then showTooltip("无效的IP地址") return end self.curReconnectTimes = self.curReconnectTimes + 1 print(string.format("%s Net:reconnect() netConfigMap = %s",self.logTag, table.tostring(self.netConfigMap))) print(string.format("%s Net:reconnect() ipIndex = %s",self.logTag, self.ipIndex)) print(string.format("%s Net:reconnect() curReconnectTimes = %s, maxReconnectTimes = %s",self.logTag, self.curReconnectTimes, self.maxReconnectTimes)) self.IP = ip self.Port = port print("尝试重连:" .. tostring(self.IP) .. ":" .. tostring(self.Port)); self.Socket:connect(self.IP, self.Port) end -- 连接服务器 function Net:connect() self:reconnect(); end -- 关闭连接 function Net:close() if self.Socket then self.Socket:close(); end end -- 是否已经连接了 function Net:isinit() return self ~= nil and self.IP ~= nil and self.Port ~= nil; end -- 是否处于链接状态 function Net:isConnected() return self.Socket:state() == NetClientState.Connected; end -- 启动网络模块 function Net:startNet() local function onState(state) if state == NetClientState.Disconnect then self.OnDisconnect() elseif state == NetClientState.Connected then --self.mNetworkFunc = {} --self.mFuncToCmd = {} --self.mNetworkFunc.get = NetworkFuncGet -- 这里触发一个socket级别的连接成功回调 app:dispatchEvent({name = "socketConnectSucceed" , net = self}); self.OnConnect() end self.OnState(state); end local function onMessage(moduleID , cmdID , statusCode , stream) -- 处理服务器消息 app:dispatchEvent{name = "netProcessMessage", moduleID = moduleID, cmdID = cmdID, statusCode = statusCode} self.OnMessage(moduleID , cmdID , statusCode , stream) end if not self.Socket then self.Socket = NetClient.new(onMessage , onState); if self.Socket.setConnectTimeout and isIOSReviewVersion() then self.Socket:setConnectTimeout(30) end if self.Socket.setWriteTimeout and isIOSReviewVersion() then self.Socket:setWriteTimeout(30) end if self.Socket.setReadTimeout and isIOSReviewVersion() then self.Socket:setReadTimeout(30) end end -- 创建新的网络连接 self:reconnect(); end -- 发送一个命令(不带用户数据)到服务器 function Net:sendCmd(moduleID , cmdID) local stream = NetStream.new(); self:send(moduleID , cmdID , stream); NetStream.delete(stream) end return Net;