You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
8.0 KiB

  1. local Net = class("Net");
  2. NetClientState =
  3. {
  4. Disconnect = 0,
  5. Connectting = 1,
  6. Connected = 2,
  7. }
  8. local function gettable(tab , key , defaultValue)
  9. local value = tab[key];
  10. if value then
  11. return value
  12. else
  13. value = defaultValue
  14. tab[key] = value
  15. return value
  16. end
  17. end
  18. local function NetworkFuncGet(self , moduleID)
  19. return gettable(self, moduleID, {
  20. get = function(self , cmdID)
  21. return gettable(self, cmdID, {
  22. funcs = {},
  23. callbacks = {},
  24. dirty = true,
  25. insert = function(self , func)
  26. self.funcs[func] = 1
  27. self.dirty = true
  28. end,
  29. remove = function(self , func)
  30. self.funcs[func] = nil
  31. self.dirty = true
  32. end,
  33. })
  34. end,
  35. })
  36. end
  37. -- 构造函数
  38. function Net:ctor()
  39. -- 保存模块->命令->函数的对应关系
  40. self.mNetworkFunc = {}
  41. -- 保存函数->模块命令的对应关系
  42. self.mFuncToCmd = {}
  43. self.mNetworkFunc.get = NetworkFuncGet
  44. self.logTag = ""
  45. -- 所有IP
  46. self.netConfigMap = {}
  47. -- 当前IP的索引
  48. self.ipIndex = nil;
  49. -- 当前IP使用的次数
  50. self.curReconnectTimes = 0;
  51. -- 每个IP最多重连3次
  52. self.maxReconnectTimes = 3;
  53. self.OnState = function(state)end;
  54. -- 网络消息处理函数
  55. local function onNetworkMsg(moduleID , cmdID , statusCode , stream)
  56. if statusCode ~= 0 then
  57. showTooltip("statusCode = "..statusCode);
  58. print(string.format("接受消息:moduleID[%d] cmdID[%#x] statusCode[%d]", moduleID, cmdID, statusCode));
  59. else
  60. print(string.format("接受消息:moduleID[%d] cmdID[%#x] statusCode[%d] size[%d]", moduleID, cmdID, statusCode, NetStream.getReadSize(stream)));
  61. end
  62. local mod = self.mNetworkFunc[moduleID];
  63. if mod then
  64. local cmd = mod[cmdID];
  65. if cmd then
  66. if cmd.dirty then
  67. cmd.dirty = false
  68. cmd.callbacks = {}
  69. for i,v in pairs(cmd.funcs) do
  70. cmd.callbacks[i] = v
  71. end
  72. end
  73. local funcs = cmd.callbacks
  74. for func,v in pairs(funcs) do
  75. NetStream.reset(stream);
  76. func(statusCode , stream);
  77. end
  78. if cmd.dirty then
  79. cmd.callbacks = {}
  80. end
  81. end
  82. end
  83. end
  84. self.OnMessage = onNetworkMsg
  85. self.OnConnect = function()
  86. log(self.logTag.."net::OnConnect()")
  87. self.curReconnectTimes = 0;
  88. app:dispatchEvent({name = "onConnect" , net = self});
  89. end
  90. self.OnConnectting = function()
  91. log(self.logTag.."net::OnConnectting()")
  92. app:dispatchEvent({name = "onConnectting" , net = self});
  93. end
  94. self.OnDisconnect = function()
  95. log(self.logTag.."net::OnDisconnect()")
  96. app:dispatchEvent({name = "onDisconnect" , net = self});
  97. end
  98. end
  99. -- 清空网络端口列表
  100. function Net:clearIpList()
  101. -- 所有IP
  102. self.netConfigMap = {}
  103. -- 当前IP的索引
  104. self.ipIndex = nil;
  105. -- 当前IP使用的次数
  106. self.curReconnectTimes = 0;
  107. end
  108. -- 添加网络端口列表
  109. function Net:addIp(ip, port)
  110. if not ip or not port then
  111. return
  112. end
  113. if not self.netConfigMap then
  114. self.netConfigMap = {}
  115. end
  116. table.insert(self.netConfigMap, {ip = ip, port = port})
  117. end
  118. function Net:removeIp(index)
  119. local nSize = #self.netConfigMap
  120. if tonumber(index) <= tonumber(nSize) then
  121. table.remove(self.netConfigMap, tonumber(index))
  122. end
  123. -- 可用的IP地址用完了,就重启游戏,重新拉取新配置
  124. if #self.netConfigMap <= 0 then
  125. cc.Application:getInstance():restart();
  126. return
  127. end
  128. end
  129. -- 从网络端口列表中获取一个可用的端口
  130. function Net:getIp()
  131. if not self.netConfigMap or #self.netConfigMap <= 0 then
  132. return nil
  133. end
  134. self.ipIndex = math.random(#self.netConfigMap)
  135. self.curReconnectTimes = 0;
  136. local value = self.netConfigMap[self.ipIndex]
  137. return value.ip, value.port;
  138. end
  139. -- 注册一个网络消息回调
  140. function Net:regMsg(moduleID , cmdID , func)
  141. if type(func) ~= "function" then
  142. error("regMsg时传入了不正确的function,moduleID[" .. tostring(moduleID) .. "] cmdID[" .. tostring(cmdID) .. "] func[" .. tostring(func) .. "]");
  143. return
  144. end
  145. self.mNetworkFunc:get(moduleID):get(cmdID):insert(func);
  146. self.mFuncToCmd[func] = {moduleID,cmdID};
  147. end
  148. -- 反注册一个网络消息
  149. function Net:unregMsg(func)
  150. if type(func) ~= "function" then
  151. error("unregMsg时传进来的第一个参数不是function");
  152. end
  153. local funcToCmd = self.mFuncToCmd[func];
  154. if funcToCmd == nil then
  155. return
  156. end
  157. self.mNetworkFunc:get(funcToCmd[1]):get(funcToCmd[2]):remove(func);
  158. self.mFuncToCmd[func] = nil;
  159. end
  160. -- 通过命令ID移除网络消息监听
  161. function Net:removeMsgHandler(cmdID)
  162. for func,funcToCmd in pairs(self.mFuncToCmd) do
  163. if funcToCmd[2]==cmdID then
  164. self:unregMsg(func)
  165. end
  166. end
  167. end
  168. -- 发送消息到服务器
  169. function Net:send(moduleID , cmdID , stream)
  170. print(string.format("发送消息:moduleID[%d] cmdID[%#x] size[%d]", moduleID, cmdID, NetStream.getWriteSize(stream)));
  171. -- 如果网络已经断开,则果断提示错误
  172. if self.Socket:state() ~= NetClientState.Connected then
  173. local function run()
  174. local stream = NetStream.new();
  175. self.OnMessage(moduleID , cmdID , -2 , stream);
  176. NetStream.delete(stream)
  177. end
  178. runInNextFrame(run);
  179. return;
  180. end
  181. self.Socket:send(moduleID , cmdID , stream)
  182. end
  183. -- 重新连接
  184. function Net:reconnect()
  185. self:close();
  186. self.OnConnectting()
  187. -- 从网络配置中随机连接
  188. local ip, port
  189. if not self.ipIndex then
  190. ip, port = self:getIp()
  191. end
  192. if self.curReconnectTimes < self.maxReconnectTimes then
  193. local value = self.netConfigMap[self.ipIndex]
  194. if value then
  195. ip, port = value.ip, value.port;
  196. end
  197. print(string.format("%s Net:reconnect() use old ,ip = %s, port = %s",self.logTag, ip, port))
  198. else
  199. -- 删除当前使用的ip
  200. self:removeIp(self.ipIndex)
  201. -- 重新获取新的ip
  202. ip, port = self:getIp()
  203. print(string.format("%s Net:reconnect() use new ,ip = %s, port = %s",self.logTag, ip, port))
  204. end
  205. if not ip or not port then
  206. showTooltip("无效的IP地址")
  207. return
  208. end
  209. self.curReconnectTimes = self.curReconnectTimes + 1
  210. print(string.format("%s Net:reconnect() netConfigMap = %s",self.logTag, table.tostring(self.netConfigMap)))
  211. print(string.format("%s Net:reconnect() ipIndex = %s",self.logTag, self.ipIndex))
  212. print(string.format("%s Net:reconnect() curReconnectTimes = %s, maxReconnectTimes = %s",self.logTag, self.curReconnectTimes, self.maxReconnectTimes))
  213. self.IP = ip
  214. self.Port = port
  215. print("尝试重连:" .. tostring(self.IP) .. ":" .. tostring(self.Port));
  216. self.Socket:connect(self.IP, self.Port)
  217. end
  218. -- 连接服务器
  219. function Net:connect()
  220. self:reconnect();
  221. end
  222. -- 关闭连接
  223. function Net:close()
  224. if self.Socket then
  225. self.Socket:close();
  226. end
  227. end
  228. -- 是否已经连接了
  229. function Net:isinit()
  230. return self ~= nil and self.IP ~= nil and self.Port ~= nil;
  231. end
  232. -- 是否处于链接状态
  233. function Net:isConnected()
  234. return self.Socket:state() == NetClientState.Connected;
  235. end
  236. -- 启动网络模块
  237. function Net:startNet()
  238. local function onState(state)
  239. if state == NetClientState.Disconnect then
  240. self.OnDisconnect()
  241. elseif state == NetClientState.Connected then
  242. --self.mNetworkFunc = {}
  243. --self.mFuncToCmd = {}
  244. --self.mNetworkFunc.get = NetworkFuncGet
  245. -- 这里触发一个socket级别的连接成功回调
  246. app:dispatchEvent({name = "socketConnectSucceed" , net = self});
  247. self.OnConnect()
  248. end
  249. self.OnState(state);
  250. end
  251. local function onMessage(moduleID , cmdID , statusCode , stream)
  252. -- 处理服务器消息
  253. app:dispatchEvent{name = "netProcessMessage", moduleID = moduleID, cmdID = cmdID, statusCode = statusCode}
  254. self.OnMessage(moduleID , cmdID , statusCode , stream)
  255. end
  256. if not self.Socket then
  257. self.Socket = NetClient.new(onMessage , onState);
  258. if self.Socket.setConnectTimeout and isIOSReviewVersion() then
  259. self.Socket:setConnectTimeout(30)
  260. end
  261. if self.Socket.setWriteTimeout and isIOSReviewVersion() then
  262. self.Socket:setWriteTimeout(30)
  263. end
  264. if self.Socket.setReadTimeout and isIOSReviewVersion() then
  265. self.Socket:setReadTimeout(30)
  266. end
  267. end
  268. -- 创建新的网络连接
  269. self:reconnect();
  270. end
  271. -- 发送一个命令(不带用户数据)到服务器
  272. function Net:sendCmd(moduleID , cmdID)
  273. local stream = NetStream.new();
  274. self:send(moduleID , cmdID , stream);
  275. NetStream.delete(stream)
  276. end
  277. return Net;