###5.3.3. 编码方法Encode
// // 摘要: // 编码,此应用不需要编码,只需解码, // 按长度将粘包划分成多个数据包 // // 参数: // context: // // msg: protected override object Encode(IHandlerContext context, Packet msg) { return msg; }这里无需编码,故直接返回msg。
###5.3.4. 解码方法Decode
// // 摘要: // 解码 // // 参数: // context: // // pk: protected override IList<Packet> Decode(IHandlerContext context, Packet pk) { IExtend extend = context.Owner as IExtend; LengthCodec packetCodec = extend["Codec"] as LengthCodec; if (packetCodec == null) { IExtend extend2 = extend; LengthCodec obj = new LengthCodec { Expire = Expire, GetLength = ((Packet p) => MessageCodec<Packet>.GetLength(p, Offset, Size)) }; packetCodec = obj; extend2["Codec"] = obj; } Console.WriteLine("报文解码前:{0}", BitConverter.ToString(pk.ToArray())); IList<Packet> list = packetCodec.Parse(pk); Console.WriteLine("报文解码"); foreach (var item in list) { Console.WriteLine("粘包处理结果:{0}", BitConverter.ToString(item.ToArray())); } return list; }####5.3.4.1.解码步骤1——实例化长度解码器对象 实例化长度解码器完成之后,并将其添加到字典中去。
IExtend extend2 = extend; LengthCodec obj = new LengthCodec { Expire = Expire, GetLength = ((Packet p) => MessageCodec<Packet>.GetLength(p, Offset, Size)) }; packetCodec = obj; extend2["Codec"] = obj;####5.3.4.2.解码步骤2——将解码前的报文打印 此步骤非必须,为了最后能让读者看到效果增加。
Console.WriteLine("报文解码前:{0}", BitConverteToString(pk.ToArray()));####5.3.4.3.解码步骤3——将报文进行解码
IList<Packet> list = packetCodec.Parse(pk);解码代码如下:
// // 摘要: // 分析数据流,得到一帧数据 // // 参数: // pk: // 待分析数据包 public virtual IList<Packet> Parse(Packet pk) { MemoryStream stream = Stream; bool num = stream == null || stream.Position < 0 || stream.Position >= stream.Length; List<Packet> list = new List<Packet>(); if (num) { if (pk == null) { return list.ToArray(); } int i; int num2; for (i = 0; i < pk.Total; i += num2) { Packet packet = pk.Slice(i); num2 = GetLength(packet); Console.WriteLine(" pk. GetLength(packet):{0}", num2); if (num2 <= 0 || num2 > packet.Total) { break; } packet.Set(packet.Data, packet.Offset, num2); list.Add(packet); } if (i == pk.Total) { return list.ToArray(); } pk = pk.Slice(i); } lock (this) { CheckCache(); stream = Stream; if (pk != null && pk.Total > 0) { long position = stream.Position; stream.Position = stream.Length; pk.CopyTo(stream); stream.Position = position; } while (stream.Position < stream.Length) { Packet packet2 = new Packet(stream); int num3 = GetLength(packet2); if (num3 <= 0 || num3 > packet2.Total) { break; } packet2.Set(packet2.Data, packet2.Offset, num3); list.Add(packet2); stream.Seek(num3, SeekOrigin.Current); } if (stream.Position >= stream.Length) { stream.SetLength(0L); stream.Position = 0L; } return list; } }解码核心代码如下: 即获得每帧报文的长度,通过委托方法 GetLength(packet),然后循环所有粘包报文,根据每帧报文的长度分割保存到list中去,最后返回list。list的每个元素会触发message接收事件。
委托的使用请敬请关注下一篇,委托代码详见6.
for (i = 0; i < pk.Total; i += num2) { Packet packet = pk.Slice(i); num2 = GetLength(packet); Console.WriteLine(" pk. GetLength(packet):{0}", num2); if (num2 <= 0 || num2 > packet.Total) { break; } packet.Set(packet.Data, packet.Offset, num2); list.Add(packet); }####5.3.4.4.将粘包处理结果进行打印
foreach (var item in list) { Console.WriteLine("粘包处理结果:{0}"BitConverter.ToString(item.ToArray())); }###5.3.5.清空粘包编码器 该方法由NewLife.Net网络库调用,我们无需关心。
// // 摘要: // 连接关闭时,清空粘包编码器 // // 参数: // context: // // reason: public override bool Close(IHandlerContext contextstring reason) { IExtend extend = context.Owner as IExtend; if (extend != null) { extend["Codec"] = null; } return base.Close(context, reason); }###5.3.6.完整拆分粘包解码器代码
// 摘要: // 长度字段作为头部 // public class StickPackageSplit : MessageCodec<Packet> { // // 摘要: // 长度所在位置 public int Offset { get; set; } = 5; // // 摘要: // 长度占据字节数,1/2/4个字节,0表示压缩编码整数,默认2 public int Size { get; set; } = 2; // // 摘要: // 过期时间,超过该时间后按废弃数据处理,默认500ms public int Expire { get; set; } = 500; // // 摘要: // 编码,此应用不需要编码,只需解码, // 按长度将粘包划分成多个数据包 // // 参数: // context: // // msg: protected override object Encode(IHandlerContext context, Packet msg) { return msg; } // // 摘要: // 解码 // // 参数: // context: // // pk: protected override IList<Packet> Decode(IHandlerContext context, Packet pk) { IExtend extend = context.Owner as IExtend; LengthCodec packetCodec = extend["Codec"] as LengthCodec; if (packetCodec == null) { IExtend extend2 = extend; LengthCodec obj = new LengthCodec { Expire = Expire, GetLength = ((Packet p) => MessageCodec<Packet>.GetLength(p, Offset, Size)) }; packetCodec = obj; extend2["Codec"] = obj; } Console.WriteLine("报文解码前:{0}", BitConverter.ToString(pk.ToArray())); IList<Packet> list = packetCodec.Parse(pk); Console.WriteLine("报文解码"); foreach (var item in list) { Console.WriteLine("粘包处理结果:{0}", BitConverter.ToString(item.ToArray())); } return list; } // // 摘要: // 连接关闭时,清空粘包编码器 // // 参数: // context: // // reason: public override bool Close(IHandlerContext context, string reason) { IExtend extend = context.Owner as IExtend; if (extend != null) { extend["Codec"] = null; } return base.Close(context, reason); } }