网络游戏客户端通信模块简单实现
网络游戏客户端通信模块的简单实现如下,未经充分测试,功能也不完善,纯实学习,积累之用。
1. 首先是发送的包的封装,与服务端约定好的协议,代码如下:
1 using Cmd; 2 using ProtoBuf.Meta; 3 using System; 4 using System.Collections.Generic; 5 using System.IO; 6 7 namespace Network 8 { 9 /// <summary> 10 /// 发送的包,包体结构如下: 11 /// 1. 包体长度(4字节) 12 /// 2. 签名(4字节) 13 /// 3. protoId(2字节) 14 /// 4. 序列id(4字节) 15 /// 5. 包体 16 /// </summary> 17 public class SendingPacket 18 { 19 static uint s_lastSequenceId; // 上一次的序列id 20 21 uint m_length; // 包长度(4字节) 22 uint m_sign; // 签名(4字节) 23 ushort m_protoId; // protoId(2字节) 24 uint m_sequenceId; // 序列id(4字节) 25 MemoryStream m_body = new MemoryStream(); // 包体 26 27 // Properties 28 public Action<ReturnPacket> OnPacketReturn { get; set; } 29 public EProtoId? ExpectedReturnId { get; set; } 30 public bool SendWait { get; set; } 31 public EProtoId ProtoId { get { return (EProtoId)m_protoId; } } 32 33 #region static 34 35 // 序列id会不断自增 36 static uint GetSequenceId() 37 { 38 return ++s_lastSequenceId; 39 } 40 41 // 计算签名 42 static uint CalcSign(byte[] bytes) 43 { 44 if (bytes == null) 45 throw new ArgumentNullException("bytes"); 46 47 const string str = "45ddk124k55k3l9djdssk9gk1zc6bn9cpo4afcx4322121ddafadfasdfazctewq"; 48 uint[] tempArray = new uint[256]; 49 50 for (int i = 0; i < tempArray.Length; i++) 51 { 52 if (i < str.Length) 53 tempArray[i] = str[i]; 54 } 55 56 int clampI = 0; 57 uint sign = 0; 58 59 for (int i = 0; i < tempArray.Length; i++) 60 { 61 if (clampI >= bytes.Length) 62 clampI %= bytes.Length; 63 64 byte b = bytes[clampI]; 65 uint r = 0; 66 67 switch ((clampI + i) % 4) 68 { 69 case 0: 70 r = (uint)(b | tempArray[i]); 71 break; 72 case 1: 73 r = (uint)(b + tempArray[i]); 74 break; 75 case 2: 76 r = (uint)(b * 2); 77 break; 78 case 3: 79 r = (uint)(b > tempArray[i] ? (b - tempArray[i]) : (tempArray[i] - b)); 80 break; 81 default: 82 throw new InvalidOperationException("Unexpected result: " + ((clampI + i) % 4)); 83 } 84 r %= 128; 85 86 sign += r; 87 88 clampI += (int)tempArray[i]; 89 } 90 91 return sign % 1024; 92 } 93 94 #endregion 95 96 public SendingPacket(EProtoId protoId, object body) 97 { 98 if (body == null) 99 throw new ArgumentNullException("body"); 100 101 m_protoId = (ushort)protoId; 102 103 // 序列化 104 RuntimeTypeModel.Default.Serialize(m_body, body); 105 106 // length 107 m_length = (uint)(m_body.Length + 4 + 4 + 2); 108 m_length |= 0x20000000; // 与服务端的约定,最高位为1,此时服务端会验证签名 109 } 110 111 /// <summary> 112 /// 每次发包都需要更新序列id和签名 113 /// </summary> 114 public void UpdateSequenceId() 115 { 116 m_sequenceId = GetSequenceId(); 117 118 // sign 119 var forSign = new List<byte>(); 120 { 121 forSign.AddRange(BitConverter.GetBytes(m_protoId)); 122 forSign.AddRange(BitConverter.GetBytes(m_sequenceId)); 123 forSign.AddRange(m_body.ToArray()); 124 } 125 m_sign = CalcSign(forSign.ToArray()); 126 } 127 128 public byte[] GetBytes() 129 { 130 var list = new List<byte>(); 131 { 132 list.AddRange(BitConverter.GetBytes(m_length)); 133 list.AddRange(BitConverter.GetBytes(m_sign)); 134 list.AddRange(BitConverter.GetBytes(m_protoId)); 135 list.AddRange(BitConverter.GetBytes(m_sequenceId)); 136 list.AddRange(m_body.ToArray()); 137 } 138 139 return list.ToArray(); 140 } 141 } 142 }
2. 收到的包的封装,代码如下:
1 using Cmd; 2 using System; 3 4 namespace Network 5 { 6 /// <summary> 7 /// 接收到的包,结构如下: 8 /// 1. 包体长度(4字节) 9 /// 2. protoId(2字节) 10 /// 3. 包体 11 /// </summary> 12 public class ReturnPacket 13 { 14 ushort m_protoId; 15 byte[] m_body; 16 17 // Properties 18 public EProtoId ProtoId { get { return (EProtoId)m_protoId; } } 19 public byte[] Body { get { return m_body; } } 20 21 public ReturnPacket(ushort protoId, byte[] body) 22 { 23 if (body == null) 24 throw new ArgumentNullException("body"); 25 26 m_protoId = protoId; 27 m_body = body; 28 } 29 } 30 }
3. 解包工具,代码如下:
1 using System; 2 using UnityEngine; 3 4 namespace Network 5 { 6 /// <summary> 7 /// 解包工具 8 /// </summary> 9 class UnpackTool 10 { 11 const int HeadLength = 6; 12 13 byte[] m_readBuffer = new byte[256 * 1024]; 14 int m_beginOffset = 0; 15 int m_endOffset = 0; 16 17 public void Reset() 18 { 19 m_beginOffset = 0; 20 m_endOffset = 0; 21 } 22 23 public void UnpackData(byte[] receivedBuffer, int receivedLength, Action<ReturnPacket> unpackCallback) 24 { 25 if (receivedLength <= 0) 26 return; 27 28 Array.Copy(receivedBuffer, 0, m_readBuffer, m_endOffset, receivedLength); 29 m_endOffset += receivedLength; 30 31 while (m_endOffset - m_beginOffset >= HeadLength) 32 { 33 int bodyLen = BitConverter.ToInt32(m_readBuffer, m_beginOffset) - 2; 34 int packetLen = bodyLen + 4 + 2; 35 36 if (m_endOffset - m_beginOffset < packetLen) 37 { 38 Debug.LogError(string.Format("Data not enought, bodyLen={0}, m_beginOffset={1}, m_endOffset={2}", bodyLen, m_beginOffset, m_endOffset)); 39 break; 40 } 41 42 UInt16 protoId = BitConverter.ToUInt16(m_readBuffer, m_beginOffset + 4); 43 if (protoId == 256)//特殊处理,这个包如果id是256,那其实是服务端对于我发给他的心跳包的原样返回,由于小根转换的原因会反一反,其实真实id是1,256这个数后端说是不会主动发过来的。 44 { 45 // [dev] ??? 16位的数最大值为255,怎么可能到256,逗我? 46 Debug.LogError("protoId is: " + protoId); 47 protoId = 1; 48 } 49 50 //Debug.Log("protoId:0x" + Convert.ToString(protoId, 16) + ",len:" + bodyLen); 51 byte[] cmdBytes = new byte[bodyLen]; 52 Array.Copy(m_readBuffer, m_beginOffset + 4 + 2, cmdBytes, 0, bodyLen); 53 m_beginOffset += packetLen; 54 55 if (m_beginOffset >= (m_readBuffer.Length / 2)) 56 { 57 int offset = m_endOffset - m_beginOffset; 58 Array.Copy(m_readBuffer, m_beginOffset, m_readBuffer, 0, offset); 59 m_endOffset = offset; 60 m_beginOffset = 0; 61 } 62 63 if (unpackCallback != null) 64 { 65 var p = new ReturnPacket(protoId, cmdBytes); 66 unpackCallback(p); 67 } 68 } 69 } 70 } 71 }
4. Socket类,代码如下:
1 using Cmd; 2 using ProtoBuf; 3 using System; 4 using System.Collections.Generic; 5 using System.ComponentModel; 6 using System.IO; 7 using System.Linq; 8 using System.Net; 9 using System.Net.Sockets; 10 using System.Threading; 11 using UnityEngine; 12 using SystemThreadPriority = System.Threading.ThreadPriority; 13 14 namespace Network 15 { 16 // 为兼容老接口 17 public enum NetworkDataType 18 { 19 SendWait, // 发送,并等待返回 20 SendOnly, // 只发送 21 } 22 23 public class NetworkSocket 24 { 25 const float DurationToTurnFlower = 1.2f; // 发包时,从锁屏到转菊花的时间 26 const float MaxSendingDuration = 3f; // 发送的最大时间,超过此时间将会重连,或断开连接 27 const int MaxResendTimes = 3; // 最大重发次数 28 29 // 阻塞 30 float m_blockTimer; 31 BlockState m_blockState = BlockState.Idle; 32 public event Action EventLockScreen; 33 public event Action EventTurnFlower; 34 public event Action EventEndBlock; 35 36 // 事件 37 public event Action<NetworkSocket> EventDisconnect; 38 public event Action<Action> EventRelogin; 39 Action m_eventConnectedSucceed; 40 Action m_eventConnectedFailed; 41 Action m_eventReloginSucceed; 42 43 TcpClient m_tcpClient; 44 string m_host; 45 int m_port; 46 NetworkState m_state = NetworkState.Disconnecting; 47 48 // 发包 49 Queue<SendingPacket> m_forSendingPackets = new Queue<SendingPacket>(); // 要发送的包的队列 50 SendingPacket m_sendingPacket; // 当前正在发送的包 51 float m_sendingTimer; 52 53 // 重发 54 SendingPacket m_resendPacket; // 重发的包 55 float m_resendTimes; // 重发次数 56 57 // 收包 58 UnpackTool m_unpackTool = new UnpackTool(); // 解包工具 59 byte[] m_receivedBuffer = new byte[256 * 1024]; // 收包临时缓存 60 Thread m_listenInThread; // 监听收包线程 61 Queue<ReturnPacket> m_receivedPackets = new Queue<ReturnPacket>(); // 收到的包的缓存 62 63 #region Properties 64 65 public bool Connected 66 { 67 get { return m_tcpClient != null && m_tcpClient.Connected; } 68 } 69 70 NetworkState State 71 { 72 get { return m_state; } 73 set 74 { 75 //Debug.Log(string.Format("#[Network]Change network state from {0} to {1}", m_state, value)); 76 m_state = value; 77 } 78 } 79 80 #endregion 81 82 #region State 83 84 enum NetworkState 85 { 86 Connecting, // 连接中 87 ConnectedSucceed, // 连接成功 88 ConnectedFailed, // 连接失败 89 90 Idle, // 空闲 91 92 Sending, // 发送中 93 94 Resend, // 重发 95 Resending, // 重发中 96 97 Disconnect, // 断开连接 98 Disconnecting, // 连接断开中 99 } 100 101 // 阻塞状态管理 102 enum BlockState 103 { 104 Idle, 105 LockScreen, 106 ScreenLocking, 107 TurnFlower, 108 FlowerTurning, 109 EndBlock, 110 } 111 112 #endregion 113 114 #region static 115 116 public static EProtoId? GetProtoId(Type type) 117 { 118 var idProp = type.GetProperty("id"); 119 if (idProp == null) 120 { 121 Debug.LogError("#[Network]idProp==null, type: " + type); 122 return null; 123 } 124 125 var attributes = idProp.GetCustomAttributes(typeof(DefaultValueAttribute), false); 126 if (attributes == null || attributes.Length <= 0) 127 { 128 Debug.LogError("#[Network]attributes == null || attributes.Length <= 0, type: " + type); 129 return null; 130 } 131 132 var attribute = attributes[0] as DefaultValueAttribute; 133 if (attribute == null) 134 { 135 Debug.LogError("#[Network]attribute==null, type: " + type); 136 return null; 137 } 138 139 return (EProtoId)attribute.Value; 140 } 141 142 #endregion 143 144 #region 状态机 & 监听回包 145 146 public void Update() 147 { 148 #region 阻塞 149 150 bool blocking = m_forSendingPackets.Count > 0 && State != NetworkState.Disconnecting; 151 152 switch (m_blockState) 153 { 154 case BlockState.Idle: 155 if (blocking) 156 m_blockState = BlockState.LockScreen; 157 break; 158 159 case BlockState.LockScreen: 160 m_blockState = BlockState.ScreenLocking; 161 m_blockTimer = 0; 162 if (EventLockScreen != null) 163 EventLockScreen(); 164 break; 165 166 case BlockState.ScreenLocking: 167 if (blocking) 168 { 169 m_blockTimer += Time.deltaTime; 170 if (m_blockTimer >= DurationToTurnFlower) 171 m_blockState = BlockState.TurnFlower; 172 } 173 else 174 m_blockState = BlockState.EndBlock; 175 break; 176 177 case BlockState.TurnFlower: 178 m_blockState = BlockState.FlowerTurning; 179 if (EventTurnFlower != null) 180 EventTurnFlower(); 181 break; 182 183 case BlockState.FlowerTurning: 184 if (!blocking) 185 m_blockState = BlockState.EndBlock; 186 break; 187 188 case BlockState.EndBlock: 189 m_blockState = BlockState.Idle; 190 if (EventEndBlock != null) 191 EventEndBlock(); 192 break; 193 194 default: 195 throw new InvalidOperationException("Unknown block state: " + m_blockState); 196 } 197 198 #endregion 199 200 #region 状态机 201 202 switch (m_state) 203 { 204 // 连接 205 case NetworkState.Connecting: 206 if (Connected) 207 State = NetworkState.ConnectedSucceed; 208 break; 209 210 case NetworkState.ConnectedSucceed: 211 { 212 State = NetworkState.Idle; 213 if (m_eventConnectedSucceed != null) 214 { 215 m_eventConnectedSucceed(); 216 m_eventConnectedSucceed = null; 217 m_eventConnectedFailed = null; 218 } 219 } 220 break; 221 222 case NetworkState.ConnectedFailed: 223 { 224 State = NetworkState.Disconnect; 225 if (m_eventConnectedFailed != null) 226 { 227 m_eventConnectedFailed(); 228 m_eventConnectedSucceed = null; 229 m_eventConnectedFailed = null; 230 } 231 } 232 break; 233 234 // 空闲 235 case NetworkState.Idle: 236 { 237 // 发包 238 if (m_forSendingPackets.Count > 0) 239 { 240 m_sendingTimer = 0; 241 ReallySend(); 242 } 243 244 // 重发成功的时机 245 if (m_resendPacket != null) 246 { 247 if (!m_forSendingPackets.Contains(m_resendPacket)) // 表示重发成功 248 { 249 m_resendPacket = null; 250 m_resendTimes = 0; 251 252 if (m_eventReloginSucceed != null) 253 { 254 m_eventReloginSucceed(); 255 m_eventReloginSucceed = null; 256 } 257 } 258 } 259 } 260 break; 261 262 case NetworkState.Sending: 263 { 264 m_sendingTimer += Time.deltaTime; 265 if (m_sendingTimer > MaxSendingDuration) 266 State = m_resendTimes < MaxResendTimes ? NetworkState.Resend : NetworkState.Disconnect; 267 } 268 break; 269 270 // 重发 271 case NetworkState.Resend: 272 { 273 State = NetworkState.Resending; 274 275 m_resendTimes++; 276 277 // 第一次重连 278 if (m_resendPacket == null) 279 { 280 // 为什么要这样做?因为重连操作,连接成功之后要优先发重登录的包。 281 m_resendPacket = m_forSendingPackets.FirstOrDefault(p => p.SendWait); 282 var tempQueue = new Queue<SendingPacket>(m_forSendingPackets); // 先出队 283 m_forSendingPackets.Clear(); 284 EventRelogin(() => 285 { 286 for (int i = 0; i < tempQueue.Count; i++) 287 m_forSendingPackets.Enqueue(tempQueue.Dequeue()); // 再入队 288 }); 289 } 290 else 291 { 292 EventRelogin(null); 293 } 294 295 Debug.Log("#[Network]断线重连,重连次数: " + m_resendTimes); 296 } 297 break; 298 299 case NetworkState.Resending: 300 break; 301 302 // 断开连接 303 case NetworkState.Disconnect: 304 { 305 m_resendTimes = 0; 306 State = NetworkState.Disconnecting; 307 if (EventDisconnect != null) 308 EventDisconnect(this); 309 } 310 break; 311 312 case NetworkState.Disconnecting: 313 // 此时应该在弹框中 314 break; 315 316 default: 317 throw new InvalidOperationException("Unknown state: " + m_state); 318 } 319 320 #endregion 321 322 #region 监听处理回包 323 324 // 监听 325 if (Connected) 326 { 327 if (m_listenInThread == null) 328 m_listenInThread = new Thread(obj => ListenInReturnPackets()); 329 330 if (m_listenInThread.ThreadState == ThreadState.Unstarted) 331 { 332 m_listenInThread.Priority = SystemThreadPriority.AboveNormal; 333 m_listenInThread.Start(); 334 } 335 } 336 else 337 { 338 if (m_listenInThread != null && m_listenInThread.IsAlive) 339 m_listenInThread.Abort(); 340 } 341 342 // 处理回包 343 if (m_receivedPackets.Count > 0) 344 ProcessReturnPackets(); 345 346 #endregion 347 } 348 349 #endregion 350 351 #region 连接 352 353 public void Connect(string host, int port) 354 { 355 Connect(host, port, null, null); 356 } 357 358 public void Connect(string host, int port, Action onSucceed, Action onFailed) 359 { 360 if (string.IsNullOrEmpty(host)) 361 throw new ArgumentException("host"); 362 363 if (State == NetworkState.Connecting) 364 return; 365 366 State = NetworkState.Connecting; 367 368 // 断开原有连接 369 Disconnect(); 370 371 m_eventConnectedSucceed = onSucceed; 372 m_eventConnectedFailed = onFailed; 373 m_host = host; 374 m_port = port; 375 376 IPAddress[] addresses = null; 377 try 378 { 379 addresses = Dns.GetHostAddresses(host); 380 } 381 catch (Exception ex) 382 { 383 Debug.LogError("#[Network]Dns.GetHostAddresses(ip) failed, ex: " + ex); 384 } 385 386 // 是否是ipv6 387 bool isIpv6 = addresses != null && addresses.Length > 0 && addresses[0].AddressFamily == AddressFamily.InterNetworkV6; 388 389 try 390 { 391 m_tcpClient = isIpv6 ? new TcpClient(AddressFamily.InterNetworkV6) : new TcpClient(); 392 m_tcpClient.BeginConnect(host, port, r => 393 { 394 if (Connected) 395 { 396 Debug.Log(string.Format("#[Network]Connect to server succeed, host: {0}, port: {1}, ipv6: {2}", host, port, isIpv6)); 397 State = NetworkState.ConnectedSucceed; 398 } 399 else 400 { 401 Debug.Log(string.Format("#[Network]Connect to server failed, host: {0}, port: {1}, ipv6: {2}", host, port, isIpv6)); 402 State = NetworkState.ConnectedFailed; 403 } 404 }, null); 405 } 406 catch (Exception ex) 407 { 408 Debug.Log(string.Format("#[Network]Connect to server failed, host: {0}, port: {1}, ipv6: {2}, ex: {2}", host, port, isIpv6, ex)); 409 State = NetworkState.ConnectedFailed; 410 } 411 } 412 413 public void Reconnect() 414 { 415 Reconnect(null, null); 416 } 417 418 public void Reconnect(Action onSucceed, Action onFailed) 419 { 420 if (!string.IsNullOrEmpty(m_host)) // 是否有连接过 421 Connect(m_host, m_port, onSucceed, onFailed); 422 } 423 424 /// <summary> 425 /// 断线重连 426 /// </summary> 427 public void Relogin(Action callback) 428 { 429 State = NetworkState.Resend; 430 m_eventReloginSucceed = callback; 431 } 432 433 /// <summary> 434 /// 断开连接 435 /// </summary> 436 public void Disconnect() 437 { 438 // close socket 439 if (Connected) 440 { 441 try 442 { 443 m_tcpClient.GetStream().Close(); 444 m_tcpClient.Close(); 445 } 446 catch (Exception ex) 447 { 448 Debug.LogError("#[Network]Error when disconnect socket, ex: " + ex); 449 m_tcpClient.Close(); 450 } 451 } 452 m_tcpClient = null; 453 454 if (m_listenInThread != null && m_listenInThread.IsAlive) 455 m_listenInThread.Abort(); 456 m_listenInThread = null; 457 } 458 459 public void SetToNoDelayMode() 460 { 461 if (m_tcpClient != null) 462 { 463 m_tcpClient.NoDelay = true; 464 m_tcpClient.ReceiveBufferSize = 32768; 465 m_tcpClient.SendBufferSize = 32768; 466 } 467 } 468 469 #endregion 470 471 #region 发包 472 473 // 发包,为兼容老接口。 474 public bool Send<T>(T obj, NetworkDataType option = NetworkDataType.SendOnly, EProtoId? returnId = null) 475 where T : class 476 { 477 if (option == NetworkDataType.SendWait) 478 { 479 var sendId = GetProtoId(typeof(T)); 480 if (sendId == null) 481 { 482 Debug.LogError(string.Format("#[Network]Send failed, cann't get EProtoId, send type: {0}.", typeof(T))); 483 return false; 484 } 485 486 Debug.Log("#[Network]SendWait: " + sendId.Value); 487 488 var p = new SendingPacket(sendId.Value, obj) 489 { 490 SendWait = true, 491 ExpectedReturnId = returnId, 492 OnPacketReturn = ret => 493 { 494 NCConfig.OnReceiveMessageHandler callback; 495 if (NCConfig.dictCallback.TryGetValue(ret.ProtoId, out callback)) 496 { 497 var retObj = NCConfigUnpack.GetProtocolObject(ret.ProtoId, ret.Body); 498 callback(retObj); 499 } 500 } 501 }; 502 503 m_forSendingPackets.Enqueue(p); 504 return true; 505 } 506 else 507 { 508 return SendOnly<T>(obj); 509 } 510 } 511 512 // 发包,等待回包模式 513 public bool SendWait<T1, T2>(T1 obj, Action<T2> onReturn) 514 where T1 : class 515 where T2 : class 516 { 517 var sendId = GetProtoId(typeof(T1)); 518 var returnId = GetProtoId(typeof(T2)); 519 if (sendId == null || returnId == null) 520 { 521 Debug.LogError(string.Format("#[Network]Send wait failed, cann't get EProtoId, send type: {0}, return type: {1}", typeof(T1), typeof(T2))); 522 return false; 523 } 524 525 Debug.Log("#[Network]SendWait: " + sendId.Value); 526 527 var p = new SendingPacket(sendId.Value, obj); 528 p.SendWait = true; 529 p.ExpectedReturnId = returnId.Value; 530 p.OnPacketReturn = (ret) => 531 { 532 var stream = new MemoryStream(ret.Body); 533 var t2Obj = Serializer.Deserialize<T2>(stream); 534 if (t2Obj != null) 535 onReturn(t2Obj); 536 else 537 Debug.LogError("#[Network]Cann't convert return packet to type: " + typeof(T2)); 538 }; 539 m_forSendingPackets.Enqueue(p); 540 return true; 541 } 542 543 // 发包,只发送,不等待回包模式 544 public bool SendOnly<T>(T obj) where T : class 545 { 546 var protoId = GetProtoId(typeof(T)); 547 if (protoId == null) 548 { 549 Debug.LogError("#[Network]Send only failed, cann't get EProtoId, type: " + typeof(T)); 550 return false; 551 } 552 553 Debug.Log("#[Network]SendOnly: " + protoId.Value); 554 555 var p = new SendingPacket(protoId.Value, obj); 556 p.SendWait = false; 557 m_forSendingPackets.Enqueue(p); 558 return true; 559 } 560 561 void ReallySend() 562 { 563 if (!Connected) 564 { 565 Reconnect(); 566 return; 567 } 568 569 var p = m_forSendingPackets.Peek(); 570 if (p == null) 571 throw new ArgumentNullException("p"); 572 573 try 574 { 575 var buffer = m_tcpClient.GetStream(); 576 if (buffer.CanWrite) 577 { 578 p.UpdateSequenceId(); 579 var bytes = p.GetBytes(); 580 buffer.Write(bytes, 0, bytes.Length); 581 Debug.Log(string.Format("#[Network]Really send data, protoId: {0}, send wait: {1}.", p.ProtoId, p.SendWait)); 582 583 if (p.SendWait) 584 { 585 m_sendingPacket = p; 586 State = NetworkState.Sending; 587 } 588 else 589 { 590 m_sendingPacket = null; 591 m_forSendingPackets.Dequeue(); 592 State = NetworkState.Idle; 593 } 594 } 595 else 596 { 597 Debug.LogError("#[Network]!buffer.CanWrite"); 598 } 599 } 600 catch (Exception ex) 601 { 602 Debug.LogError("#[Network]Send failed!!! ex: " + ex); 603 } 604 } 605 606 #endregion 607 608 #region 收包 609 610 // 监听回包 611 void ListenInReturnPackets() 612 { 613 while (Connected) 614 { 615 try 616 { 617 var buffer = m_tcpClient.GetStream(); 618 if (buffer.CanRead) 619 { 620 int len = buffer.Read(m_receivedBuffer, 0, m_receivedBuffer.Length); 621 if (len > 0) 622 { 623 m_unpackTool.UnpackData(m_receivedBuffer, len, p => 624 { 625 if (p == null) 626 throw new ArgumentNullException("p"); 627 628 Debug.Log("#[Network]Received packet: " + p.ProtoId); 629 630 lock (this) 631 m_receivedPackets.Enqueue(p); 632 }); 633 } 634 } 635 else 636 Debug.LogError("#[Network]!buffer.CanRead"); 637 638 Thread.Sleep(100); 639 } 640 catch (Exception ex) 641 { 642 Debug.LogError("#[Network]Read return packet failed, Exception:\n" + ex); 643 } 644 } 645 } 646 647 void ProcessReturnPackets() 648 { 649 if (m_receivedPackets.Count <= 0) 650 return; 651 652 ReturnPacket ret; 653 lock (this) 654 ret = m_receivedPackets.Dequeue(); 655 656 if (ret == null) 657 return; 658 659 if (ret.ProtoId == 0) // 心跳包 660 ProcessHeartBeat(ret); 661 else if (ret.ProtoId == EProtoId.ERROR_CODE_S) // 错误码 662 { 663 // [dev] 664 //MemoryStream buffer = new MemoryStream(ret.Body); 665 //var errorCode = Serializer.Deserialize<MessageErrorCode>(buffer); 666 //Debug.Log(string.Format("#[Network]Error code: {0}", errorCode.code)); 667 } 668 else // 正常的包 669 { 670 bool isSendWait = m_sendingPacket != null && (m_sendingPacket.ExpectedReturnId == null || m_sendingPacket.ExpectedReturnId == ret.ProtoId); 671 if (isSendWait) // 为客户端主动发,等待反馈的情况 672 { 673 if (m_sendingPacket.OnPacketReturn != null) 674 m_sendingPacket.OnPacketReturn(ret); 675 m_sendingPacket = null; 676 m_forSendingPackets.Dequeue(); 677 State = NetworkState.Idle; 678 } 679 else if (NCConfig.dictCallback.ContainsKey(ret.ProtoId)) // 可能为服务器主动推的情况 680 { 681 var callback = NCConfig.dictCallback[ret.ProtoId]; 682 var retObj = NCConfigUnpack.GetProtocolObject(ret.ProtoId, ret.Body); 683 callback(retObj); 684 } 685 else 686 { 687 Debug.LogError("#[Network]Unprocessed return packet, protoId: " + ret.ProtoId); 688 } 689 } 690 } 691 692 void ProcessHeartBeat(ReturnPacket p) 693 { 694 if (p.ProtoId != 0) 695 throw new ArgumentException("p.ProtoId != 0"); 696 697 byte[] bytes = new byte[6] { 0x2, 0x0, 0x0, 0x0, 0x0, 0x0 }; 698 699 try 700 { 701 var buffer = m_tcpClient.GetStream(); 702 if (buffer.CanWrite) 703 { 704 Debug.Log("#[Network]Send heart beat"); 705 buffer.Write(bytes, 0, 6); 706 } 707 else 708 { 709 Debug.LogError("#[Network]!buffer.CanWrite"); 710 } 711 } 712 catch (Exception ex) 713 { 714 Debug.LogError("#[Network]Send heart beat failed, ex: " + ex); 715 } 716 } 717 718 #endregion 719 } 720 }