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

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

相关文章:

  • 2021-08-12
  • 2022-12-23
  • 2021-07-06
  • 2022-12-23
  • 2021-10-20
  • 2021-12-16
  • 2021-11-10
  • 2022-02-01
猜你喜欢
  • 2022-12-23
  • 2021-04-14
  • 2022-12-23
  • 2021-12-15
  • 2021-10-29
  • 2021-12-05
  • 2021-07-09
相关资源
相似解决方案