码迷,mamicode.com
首页 > 其他好文 > 详细

网络游戏客户端通信模块简单实现

时间:2016-08-01 17:44:32      阅读:260      评论:0      收藏:0      [点我收藏+]

标签:

网络游戏客户端通信模块的简单实现如下,未经充分测试,功能也不完善,纯实学习,积累之用。

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 }
SendingPacket

 

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 }
ReturnPacket

 

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 }
UnpackTool

 

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 }
NetworkSocket

 

转载请注明出处: http://www.cnblogs.com/jietian331/p/5726332.html

网络游戏客户端通信模块简单实现

标签:

原文地址:http://www.cnblogs.com/jietian331/p/5726332.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!