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


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

    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:
    " + 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

  • 相关阅读:
    thinkphp中插入ueditor编辑器的代码
    编辑器
    php中上传图片,原生代码
    thinkphp中上传图片以及制成缩略图
    https://www.oschina.net/project/lang/19/java
    js中各种弹窗
    MYSQL数据库中中文乱码问题
    关于对CSS中超链接那部分的设置
    Collectors.groupingBy应用
    定时器算法
  • 原文地址:https://www.cnblogs.com/jietian331/p/5726332.html
Copyright © 2020-2023  润新知