RouterComponentSystem.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. using System;
  2. using System.Net;
  3. using System.Net.Sockets;
  4. using System.Runtime.InteropServices;
  5. namespace ET.Server
  6. {
  7. [EntitySystemOf(typeof(RouterComponent))]
  8. [FriendOf(typeof (RouterNode))]
  9. public static partial class RouterComponentSystem
  10. {
  11. [EntitySystem]
  12. private static void Awake(this RouterComponent self, IPEndPoint outerAddress, string innerIP)
  13. {
  14. #if UNITY_WEBGL
  15. self.OuterTcp = new WebSocketTransport(outerAddress);
  16. #else
  17. self.OuterTcp = new TcpTransport(outerAddress);
  18. self.OuterUdp = new UdpTransport(outerAddress);
  19. #endif
  20. self.InnerSocket = new UdpTransport(new IPEndPoint(IPAddress.Parse(innerIP), 0));
  21. }
  22. [EntitySystem]
  23. private static void Destroy(this RouterComponent self)
  24. {
  25. self.OuterUdp?.Dispose();
  26. self.OuterTcp?.Dispose();
  27. self.InnerSocket.Dispose();
  28. self.IPEndPoint = null;
  29. }
  30. [EntitySystem]
  31. private static void Update(this RouterComponent self)
  32. {
  33. self.OuterUdp?.Update();
  34. self.OuterTcp?.Update();
  35. self.InnerSocket.Update();
  36. long timeNow = TimeInfo.Instance.ClientNow();
  37. self.RecvOuterUdp(timeNow);
  38. self.RecvOuterTcp(timeNow);
  39. self.RecvInner(timeNow);
  40. // 每秒钟检查一次
  41. if (timeNow - self.LastCheckTime > 1000)
  42. {
  43. self.CheckConnectTimeout(timeNow);
  44. self.LastCheckTime = timeNow;
  45. }
  46. }
  47. private static IPEndPoint CloneAddress(this RouterComponent self)
  48. {
  49. IPEndPoint ipEndPoint = (IPEndPoint) self.IPEndPoint;
  50. return new IPEndPoint(ipEndPoint.Address, ipEndPoint.Port);
  51. }
  52. // 接收tcp消息
  53. private static void RecvOuterTcp(this RouterComponent self, long timeNow)
  54. {
  55. while (self.OuterTcp != null && self.OuterTcp.Available() > 0)
  56. {
  57. try
  58. {
  59. int messageLength = self.OuterTcp.Recv(self.Cache, ref self.IPEndPoint);
  60. self.RecvOuterHandler(messageLength, timeNow, self.OuterTcp);
  61. }
  62. catch (Exception e)
  63. {
  64. Log.Error(e);
  65. }
  66. }
  67. }
  68. // 接收udp消息
  69. private static void RecvOuterUdp(this RouterComponent self, long timeNow)
  70. {
  71. while (self.OuterUdp != null && self.OuterUdp.Available() > 0)
  72. {
  73. try
  74. {
  75. int messageLength = self.OuterUdp.Recv(self.Cache, ref self.IPEndPoint);
  76. self.RecvOuterHandler(messageLength, timeNow, self.OuterUdp);
  77. }
  78. catch (Exception e)
  79. {
  80. Log.Error(e);
  81. }
  82. }
  83. }
  84. private static void CheckConnectTimeout(this RouterComponent self, long timeNow)
  85. {
  86. int n = self.checkTimeout.Count < 10? self.checkTimeout.Count : 10;
  87. for (int i = 0; i < n; ++i)
  88. {
  89. uint id = self.checkTimeout.Dequeue();
  90. RouterNode node = self.GetChild<RouterNode>(id);
  91. if (node == null)
  92. {
  93. continue;
  94. }
  95. // 已经连接上了
  96. switch (node.Status)
  97. {
  98. case RouterStatus.Sync:
  99. // 超时了
  100. if (timeNow > node.LastRecvOuterTime + 10 * 1000)
  101. {
  102. self.OnError(id, ErrorCode.ERR_KcpRouterConnectFail);
  103. continue;
  104. }
  105. break;
  106. case RouterStatus.Msg:
  107. // 比session超时应该多10秒钟
  108. if (timeNow > node.LastRecvOuterTime + SessionIdleCheckerComponentSystem.SessionTimeoutTime + 10 * 1000)
  109. {
  110. self.OnError(id, ErrorCode.ERR_KcpRouterTimeout);
  111. continue;
  112. }
  113. break;
  114. default:
  115. throw new ArgumentOutOfRangeException();
  116. }
  117. self.checkTimeout.Enqueue(id);
  118. }
  119. }
  120. private static void RecvInner(this RouterComponent self, long timeNow)
  121. {
  122. while (self.InnerSocket != null && self.InnerSocket.Available() > 0)
  123. {
  124. try
  125. {
  126. int messageLength = self.InnerSocket.Recv(self.Cache, ref self.IPEndPoint);
  127. self.RecvInnerHandler(messageLength, timeNow);
  128. }
  129. catch (Exception e)
  130. {
  131. Log.Error(e);
  132. }
  133. }
  134. }
  135. private static void RecvOuterHandler(this RouterComponent self, int messageLength, long timeNow, IKcpTransport transport)
  136. {
  137. // 长度小于1,不是正常的消息
  138. if (messageLength < 1)
  139. {
  140. return;
  141. }
  142. // accept
  143. byte flag = self.Cache[0];
  144. switch (flag)
  145. {
  146. case KcpProtocalType.RouterReconnectSYN:
  147. {
  148. if (messageLength < 13)
  149. {
  150. break;
  151. }
  152. uint outerConn = BitConverter.ToUInt32(self.Cache, 1);
  153. uint innerConn = BitConverter.ToUInt32(self.Cache, 5);
  154. uint connectId = BitConverter.ToUInt32(self.Cache, 9);
  155. string realAddress = self.Cache.ToStr(13, messageLength - 13);
  156. // RouterAck之后ConnectIdNodes会删除,加入到OuterNodes中来
  157. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  158. if (routerNode == null)
  159. {
  160. Log.Info($"router create reconnect: {self.IPEndPoint} {realAddress} {outerConn} {innerConn}");
  161. routerNode = self.New(realAddress, outerConn, innerConn, connectId, self.CloneAddress());
  162. }
  163. // 不是自己的,outerConn冲突, 直接break,也就是说这个软路由上有个跟自己outerConn冲突的连接,就不能连接了
  164. // 这个路由连接不上,客户端会换个软路由,所以没关系
  165. if (routerNode.InnerConn != innerConn)
  166. {
  167. Log.Warning($"kcp router router reconnect inner conn diff1: {routerNode.OuterIpEndPoint} {(IPEndPoint) self.IPEndPoint}");
  168. break;
  169. }
  170. if (routerNode.OuterConn != outerConn)
  171. {
  172. Log.Warning($"kcp router router reconnect outer conn diff1: {routerNode.OuterIpEndPoint} {(IPEndPoint) self.IPEndPoint}");
  173. break;
  174. }
  175. // reconnect检查了InnerConn跟OuterConn,到这里肯定保证了是同一客户端, 如果connectid不一样,证明是两次不同的连接,可以删除老的连接
  176. if (routerNode.ConnectId != connectId)
  177. {
  178. Log.Warning($"kcp router router reconnect connectId diff, maybe router count too less: {connectId} {routerNode.ConnectId} {routerNode.OuterIpEndPoint} {(IPEndPoint) self.IPEndPoint}");
  179. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterSame);
  180. break;
  181. }
  182. // 校验内网地址
  183. if (routerNode.InnerAddress != realAddress)
  184. {
  185. Log.Warning($"router sync error2: {routerNode.OuterConn} {routerNode.InnerAddress} {outerConn} {realAddress}");
  186. break;
  187. }
  188. if (++routerNode.RouterSyncCount > 40)
  189. {
  190. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterRouterSyncCountTooMuchTimes);
  191. break;
  192. }
  193. routerNode.KcpTransport = transport;
  194. // 转发到内网
  195. self.Cache.WriteTo(0, KcpProtocalType.RouterReconnectSYN);
  196. self.Cache.WriteTo(1, outerConn);
  197. self.Cache.WriteTo(5, innerConn);
  198. self.InnerSocket.Send(self.Cache, 0, 9, routerNode.InnerIpEndPoint, ChannelType.Connect);
  199. if (!routerNode.CheckOuterCount(timeNow))
  200. {
  201. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterTooManyPackets);
  202. }
  203. break;
  204. }
  205. case KcpProtocalType.RouterSYN:
  206. {
  207. if (messageLength < 13)
  208. {
  209. break;
  210. }
  211. uint outerConn = BitConverter.ToUInt32(self.Cache, 1);
  212. uint innerConn = BitConverter.ToUInt32(self.Cache, 5);
  213. uint connectId = BitConverter.ToUInt32(self.Cache, 9);
  214. string realAddress = self.Cache.ToStr(13, messageLength - 13);
  215. // innerconn会在ack的时候赋值,所以routersync过程绝对是routerNode.InnerConn绝对是0
  216. if (innerConn != 0)
  217. {
  218. Log.Warning($"kcp router syn status innerConn != 0: {outerConn} {innerConn}");
  219. break;
  220. }
  221. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  222. if (routerNode == null)
  223. {
  224. routerNode = self.New(realAddress, outerConn, innerConn, connectId, self.CloneAddress());
  225. Log.Info($"router create: {realAddress} {outerConn} {innerConn} {routerNode.OuterIpEndPoint}");
  226. }
  227. if (routerNode.Status != RouterStatus.Sync)
  228. {
  229. Log.Warning($"kcp router syn status error: {outerConn} {innerConn} {routerNode.InnerConn}");
  230. break;
  231. }
  232. // innerconn会在ack的时候赋值,所以routersync过程绝对是routerNode.InnerConn绝对是0
  233. if (routerNode.InnerConn != innerConn)
  234. {
  235. Log.Warning($"kcp router syn status InnerConn != 0: {outerConn} {innerConn} {routerNode.InnerConn}");
  236. break;
  237. }
  238. if (++routerNode.RouterSyncCount > 40)
  239. {
  240. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterRouterSyncCountTooMuchTimes);
  241. break;
  242. }
  243. // 这里因为InnerConn是0,无法保证连接是同一客户端发过来的,所以这里如果connectid不同,则break。注意逻辑跟reconnect不一样
  244. if (routerNode.ConnectId != connectId)
  245. {
  246. Log.Warning($"kcp router router connect connectId diff, maybe router count too less: {connectId} {routerNode.ConnectId} {routerNode.OuterIpEndPoint} {(IPEndPoint) self.IPEndPoint}");
  247. break;
  248. }
  249. // 校验内网地址
  250. if (routerNode.InnerAddress != realAddress)
  251. {
  252. Log.Warning($"router sync error2: {routerNode.OuterConn} {routerNode.InnerAddress} {outerConn} {realAddress}");
  253. break;
  254. }
  255. routerNode.KcpTransport = transport;
  256. self.Cache.WriteTo(0, KcpProtocalType.RouterACK);
  257. self.Cache.WriteTo(1, routerNode.InnerConn);
  258. self.Cache.WriteTo(5, routerNode.OuterConn);
  259. routerNode.KcpTransport.Send(self.Cache, 0, 9, routerNode.OuterIpEndPoint, ChannelType.Accept);
  260. if (!routerNode.CheckOuterCount(timeNow))
  261. {
  262. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterTooManyPackets);
  263. }
  264. break;
  265. }
  266. case KcpProtocalType.SYN:
  267. {
  268. // 长度!=13,不是accpet消息
  269. if (messageLength != 9)
  270. {
  271. break;
  272. }
  273. uint outerConn = BitConverter.ToUInt32(self.Cache, 1); // remote
  274. uint innerConn = BitConverter.ToUInt32(self.Cache, 5);
  275. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  276. if (routerNode == null)
  277. {
  278. Log.Warning($"kcp router syn not found outer nodes: {outerConn} {innerConn}");
  279. break;
  280. }
  281. if (++routerNode.SyncCount > 20)
  282. {
  283. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterSyncCountTooMuchTimes);
  284. break;
  285. }
  286. // 校验ip,连接过程中ip不能变化, 主要防止第三方攻击,一般问题不大
  287. IPEndPoint ipEndPoint = (IPEndPoint) self.IPEndPoint;
  288. if (!Equals(routerNode.OuterIpEndPoint.Address, ipEndPoint.Address))
  289. {
  290. Log.Warning($"kcp router syn ip is diff3: {routerNode.OuterIpEndPoint.Address} {ipEndPoint.Address}");
  291. }
  292. routerNode.KcpTransport = transport;
  293. routerNode.LastRecvOuterTime = timeNow;
  294. // 转发到内网, 带上客户端的地址
  295. self.Cache.WriteTo(0, KcpProtocalType.SYN);
  296. self.Cache.WriteTo(1, outerConn);
  297. self.Cache.WriteTo(5, innerConn);
  298. byte[] addressBytes = ipEndPoint.ToString().ToByteArray();
  299. Array.Copy(addressBytes, 0, self.Cache, 9, addressBytes.Length);
  300. Log.Info($"kcp router syn: {outerConn} {innerConn} {routerNode.InnerIpEndPoint} {routerNode.OuterIpEndPoint}");
  301. self.InnerSocket.Send(self.Cache, 0, 9 + addressBytes.Length, routerNode.InnerIpEndPoint, ChannelType.Connect);
  302. if (!routerNode.CheckOuterCount(timeNow))
  303. {
  304. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterTooManyPackets);
  305. }
  306. break;
  307. }
  308. case KcpProtocalType.FIN: // 断开
  309. {
  310. // 长度!=13,不是DisConnect消息
  311. if (messageLength != 13)
  312. {
  313. break;
  314. }
  315. uint outerConn = BitConverter.ToUInt32(self.Cache, 1);
  316. uint innerConn = BitConverter.ToUInt32(self.Cache, 5);
  317. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  318. if (routerNode == null)
  319. {
  320. Log.Warning($"kcp router outer fin not found outer nodes: {outerConn} {innerConn}");
  321. break;
  322. }
  323. // 比对innerConn
  324. if (routerNode.InnerConn != innerConn)
  325. {
  326. Log.Warning($"router node innerConn error: {innerConn} {outerConn} {routerNode.Status}");
  327. break;
  328. }
  329. routerNode.KcpTransport = transport;
  330. routerNode.LastRecvOuterTime = timeNow;
  331. Log.Info($"kcp router outer fin: {outerConn} {innerConn} {routerNode.InnerIpEndPoint}");
  332. self.InnerSocket.Send(self.Cache, 0, messageLength, routerNode.InnerIpEndPoint, ChannelType.Accept);
  333. if (!routerNode.CheckOuterCount(timeNow))
  334. {
  335. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterTooManyPackets);
  336. }
  337. break;
  338. }
  339. case KcpProtocalType.MSG:
  340. {
  341. // 长度<9,不是Msg消息
  342. if (messageLength < 9)
  343. {
  344. break;
  345. }
  346. // 处理chanel
  347. uint outerConn = BitConverter.ToUInt32(self.Cache, 1); // remote
  348. uint innerConn = BitConverter.ToUInt32(self.Cache, 5); // local
  349. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  350. if (routerNode == null)
  351. {
  352. Log.Warning($"kcp router msg not found outer nodes: {outerConn} {innerConn}");
  353. break;
  354. }
  355. // 比对innerConn
  356. if (routerNode.InnerConn != innerConn)
  357. {
  358. Log.Warning($"router node innerConn error: {innerConn} {outerConn} {routerNode.Status}");
  359. break;
  360. }
  361. if (routerNode.Status != RouterStatus.Msg)
  362. {
  363. Log.Warning($"router node status error: {innerConn} {outerConn} {routerNode.Status}");
  364. break;
  365. }
  366. routerNode.KcpTransport = transport;
  367. routerNode.LastRecvOuterTime = timeNow;
  368. self.InnerSocket.Send(self.Cache, 0, messageLength, routerNode.InnerIpEndPoint, ChannelType.Connect);
  369. if (!routerNode.CheckOuterCount(timeNow))
  370. {
  371. self.OnError(routerNode.Id, ErrorCode.ERR_KcpRouterTooManyPackets);
  372. }
  373. break;
  374. }
  375. }
  376. }
  377. private static void RecvInnerHandler(this RouterComponent self, int messageLength, long timeNow)
  378. {
  379. // 长度小于1,不是正常的消息
  380. if (messageLength < 1)
  381. {
  382. return;
  383. }
  384. // accept
  385. byte flag = self.Cache[0];
  386. switch (flag)
  387. {
  388. case KcpProtocalType.RouterReconnectACK:
  389. {
  390. uint innerConn = BitConverter.ToUInt32(self.Cache, 1);
  391. uint outerConn = BitConverter.ToUInt32(self.Cache, 5);
  392. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  393. if (routerNode == null)
  394. {
  395. Log.Warning($"router node error: {innerConn} {outerConn}");
  396. break;
  397. }
  398. // 必须校验innerConn,防止伪造
  399. if (innerConn != routerNode.InnerConn)
  400. {
  401. Log.Warning(
  402. $"router node innerConn error: {innerConn} {routerNode.InnerConn} {outerConn} {routerNode.OuterConn} {routerNode.Status}");
  403. break;
  404. }
  405. // 必须校验outerConn,防止伪造
  406. if (outerConn != routerNode.OuterConn)
  407. {
  408. Log.Warning(
  409. $"router node outerConn error: {innerConn} {routerNode.InnerConn} {outerConn} {routerNode.OuterConn} {routerNode.Status}");
  410. break;
  411. }
  412. routerNode.Status = RouterStatus.Msg;
  413. routerNode.LastRecvInnerTime = timeNow;
  414. // 转发出去
  415. self.Cache.WriteTo(0, KcpProtocalType.RouterReconnectACK);
  416. self.Cache.WriteTo(1, routerNode.InnerConn);
  417. self.Cache.WriteTo(5, routerNode.OuterConn);
  418. Log.Info($"kcp router RouterAck: {outerConn} {innerConn} {routerNode.OuterIpEndPoint}");
  419. routerNode.KcpTransport.Send(self.Cache, 0, 9, routerNode.OuterIpEndPoint, ChannelType.Accept);
  420. break;
  421. }
  422. case KcpProtocalType.ACK:
  423. {
  424. uint innerConn = BitConverter.ToUInt32(self.Cache, 1); // remote
  425. uint outerConn = BitConverter.ToUInt32(self.Cache, 5); // local
  426. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  427. if (routerNode == null)
  428. {
  429. Log.Warning($"kcp router ack not found outer nodes: {outerConn} {innerConn}");
  430. break;
  431. }
  432. routerNode.Status = RouterStatus.Msg;
  433. routerNode.InnerConn = innerConn;
  434. routerNode.LastRecvInnerTime = timeNow;
  435. // 转发出去
  436. Log.Info($"kcp router ack: {outerConn} {innerConn} {routerNode.OuterIpEndPoint}");
  437. routerNode.KcpTransport.Send(self.Cache, 0, messageLength, routerNode.OuterIpEndPoint, ChannelType.Accept);
  438. break;
  439. }
  440. case KcpProtocalType.FIN: // 断开
  441. {
  442. // 长度!=13,不是DisConnect消息
  443. if (messageLength != 13)
  444. {
  445. break;
  446. }
  447. uint innerConn = BitConverter.ToUInt32(self.Cache, 1);
  448. uint outerConn = BitConverter.ToUInt32(self.Cache, 5);
  449. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  450. if (routerNode == null)
  451. {
  452. Log.Warning($"kcp router inner fin not found outer nodes: {outerConn} {innerConn}");
  453. break;
  454. }
  455. // 比对innerConn
  456. if (routerNode.InnerConn != innerConn)
  457. {
  458. Log.Warning($"router node innerConn error: {innerConn} {outerConn} {routerNode.Status}");
  459. break;
  460. }
  461. routerNode.LastRecvInnerTime = timeNow;
  462. Log.Info($"kcp router inner fin: {outerConn} {innerConn} {routerNode.OuterIpEndPoint}");
  463. routerNode.KcpTransport.Send(self.Cache, 0, messageLength, routerNode.OuterIpEndPoint, ChannelType.Accept);
  464. break;
  465. }
  466. case KcpProtocalType.MSG:
  467. {
  468. // 长度<9,不是Msg消息
  469. if (messageLength < 9)
  470. {
  471. break;
  472. }
  473. // 处理chanel
  474. uint innerConn = BitConverter.ToUInt32(self.Cache, 1); // remote
  475. uint outerConn = BitConverter.ToUInt32(self.Cache, 5); // local
  476. RouterNode routerNode = self.GetChild<RouterNode>(outerConn);
  477. if (routerNode == null)
  478. {
  479. Log.Warning($"kcp router inner msg not found outer nodes: {outerConn} {innerConn}");
  480. break;
  481. }
  482. // 比对innerConn
  483. if (routerNode.InnerConn != innerConn)
  484. {
  485. Log.Warning($"router node innerConn error: {innerConn} {outerConn} {routerNode.Status}");
  486. break;
  487. }
  488. if (routerNode.Status != RouterStatus.Msg)
  489. {
  490. Log.Warning($"router node status is not msg: {routerNode.Status}");
  491. break;
  492. }
  493. routerNode.LastRecvInnerTime = timeNow;
  494. routerNode.KcpTransport.Send(self.Cache, 0, messageLength, routerNode.OuterIpEndPoint, ChannelType.Accept);
  495. break;
  496. }
  497. }
  498. }
  499. private static RouterNode New(this RouterComponent self, string innerAddress, uint outerConn, uint innerConn, uint connectId, IPEndPoint outerIpEndPoint)
  500. {
  501. RouterNode routerNode = self.AddChildWithId<RouterNode>(outerConn);
  502. routerNode.InnerConn = innerConn;
  503. routerNode.ConnectId = connectId;
  504. routerNode.InnerIpEndPoint = NetworkHelper.ToIPEndPoint(innerAddress);
  505. routerNode.OuterIpEndPoint = outerIpEndPoint;
  506. routerNode.InnerAddress = innerAddress;
  507. routerNode.LastRecvInnerTime = TimeInfo.Instance.ClientNow();
  508. self.checkTimeout.Enqueue(outerConn);
  509. routerNode.Status = RouterStatus.Sync;
  510. Log.Info($"router new: outerConn: {outerConn} innerConn: {innerConn} {outerIpEndPoint}");
  511. return routerNode;
  512. }
  513. public static void OnError(this RouterComponent self, long id, int error)
  514. {
  515. RouterNode routerNode = self.GetChild<RouterNode>(id);
  516. if (routerNode == null)
  517. {
  518. return;
  519. }
  520. Log.Info($"router node remove: {routerNode.OuterConn} {routerNode.InnerConn} {error}");
  521. self.Remove(id);
  522. }
  523. private static void Remove(this RouterComponent self, long id)
  524. {
  525. RouterNode routerNode = self.GetChild<RouterNode>(id);
  526. if (routerNode == null)
  527. {
  528. return;
  529. }
  530. Log.Info($"router remove: {routerNode.Id} outerConn: {routerNode.OuterConn} innerConn: {routerNode.InnerConn}");
  531. routerNode.Dispose();
  532. }
  533. }
  534. }