网络游戏客户端通信模块的简单实现如下,未经充分测试,功能也不完善,纯实学习,积累之用。
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 ///10 /// 发送的包,包体结构如下: 11 /// 1. 包体长度(4字节) 12 /// 2. 签名(4字节) 13 /// 3. protoId(2字节) 14 /// 4. 序列id(4字节) 15 /// 5. 包体 16 /// 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 ActionOnPacketReturn { 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 // length107 m_length = (uint)(m_body.Length + 4 + 4 + 2);108 m_length |= 0x20000000; // 与服务端的约定,最高位为1,此时服务端会验证签名109 }110 111 /// 112 /// 每次发包都需要更新序列id和签名113 /// 114 public void UpdateSequenceId()115 {116 m_sequenceId = GetSequenceId();117 118 // sign119 var forSign = new List();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 ();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 ///7 /// 接收到的包,结构如下: 8 /// 1. 包体长度(4字节) 9 /// 2. protoId(2字节)10 /// 3. 包体11 /// 12 public class ReturnPacket13 {14 ushort m_protoId;15 byte[] m_body;16 17 // Properties18 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 ///7 /// 解包工具 8 /// 9 class UnpackTool10 {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, ActionunpackCallback)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 ActionEventDisconnect; 38 public event 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 m_forSendingPackets = new Queue (); // 要发送的包的队列 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 m_receivedPackets = new Queue (); // 收到的包的缓存 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 BlockState103 {104 Idle,105 LockScreen,106 ScreenLocking,107 TurnFlower,108 FlowerTurning,109 EndBlock,110 }111 112 #endregion113 114 #region static115 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 #endregion143 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 else174 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 #endregion199 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 (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 else291 {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 #endregion321 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 else337 {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 #endregion347 }348 349 #endregion350 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 try378 {379 addresses = Dns.GetHostAddresses(host);380 }381 catch (Exception ex)382 {383 Debug.LogError("#[Network]Dns.GetHostAddresses(ip) failed, ex: " + ex);384 }385 386 // 是否是ipv6387 bool isIpv6 = addresses != null && addresses.Length > 0 && addresses[0].AddressFamily == AddressFamily.InterNetworkV6;388 389 try390 {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 else400 {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 /// 425 /// 断线重连426 /// 427 public void Relogin(Action callback)428 {429 State = NetworkState.Resend;430 m_eventReloginSucceed = callback;431 }432 433 ///434 /// 断开连接435 /// 436 public void Disconnect()437 {438 // close socket439 if (Connected)440 {441 try442 {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 #endregion470 471 #region 发包472 473 // 发包,为兼容老接口。474 public bool Send(T obj, NetworkDataType option = NetworkDataType.SendOnly, EProtoId? returnId = null)475 where T : class476 {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 else507 {508 return SendOnly (obj);509 }510 }511 512 // 发包,等待回包模式513 public bool SendWait (T1 obj, Action onReturn)514 where T1 : class515 where T2 : class516 {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 (stream);534 if (t2Obj != null)535 onReturn(t2Obj);536 else537 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 obj) where T : class545 {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 try574 {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 else589 {590 m_sendingPacket = null;591 m_forSendingPackets.Dequeue();592 State = NetworkState.Idle;593 }594 }595 else596 {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 #endregion607 608 #region 收包609 610 // 监听回包611 void ListenInReturnPackets()612 {613 while (Connected)614 {615 try616 {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 else636 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 (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 else686 {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 try700 {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 else708 {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 #endregion719 }720 }
转载请注明出处: