发布0101
大石头 编写于 2020-01-01 23:35:09
X
using System;
using System.Collections.Generic;
using NewLife.Data;
using NewLife.Messaging;
using NewLife.Model;

namespace NewLife.Net.Handlers
{
    /// <summary>长度字段作为头部</summary>
    public class LengthFieldCodec : MessageCodec<Packet>
    {
        #region 属性
        /// <summary>长度所在位置</summary>
        public Int32 Offset { get; set; }

        /// <summary>长度占据字节数,1/2/4个字节,0表示压缩编码整数,默认2</summary>
        public Int32 Size { get; set; } = 2;

        /// <summary>过期时间,超过该时间后按废弃数据处理,默认500ms</summary>
        public Int32 Expire { get; set; } = 500;
        #endregion

        /// <summary>编码</summary>
        /// <param name="context"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        protected override Object Encode(IHandlerContext context, Packet msg)
        {
            var len = Math.Abs(Size);
            var buf = msg.Data;
            var idx = 0;
            var dlen = msg.Total;

            // 修正压缩编码
            if (len == 0) len = IOHelper.GetEncodedInt(dlen).Length;

            // 尝试退格,直接利用缓冲区
            if (msg.Offset >= len)
            {
                idx = msg.Offset - len;
                msg.Set(msg.Data, msg.Offset - len, msg.Count + len);
            }
            // 新建数据包,形成链式结构
            else
            {
                buf = new Byte[len];
                msg = new Packet(buf) { Next = msg };
            }

            switch (Size)
            {
                case 0:
                    var buf2 = IOHelper.GetEncodedInt(dlen);
                    buf.Write(idx, buf2);
                    break;
                case 1:
                    buf[idx] = (Byte)dlen;
                    break;
                case 2:
                    buf.Write((UInt16)dlen, idx);
                    break;
                case 4:
                    buf.Write((UInt32)dlen, idx);
                    break;
                case -2:
                    buf.Write((UInt16)dlen, idx, false);
                    break;
                case -4:
                    buf.Write((UInt32)dlen, idx, false);
                    break;
                default:
                    throw new NotSupportedException();
            }

            return msg;
        }

        /// <summary>解码</summary>
        /// <param name="context"></param>
        /// <param name="pk"></param>
        /// <returns></returns>
        protected override IList<Packet> Decode(IHandlerContext context, Packet pk)
        {
            var ss = context.Owner as IExtend;
            var pc = ss["Codec"] as PacketCodec;
            if (pc == null) ss["Codec"] = pc = new PacketCodec { Expire = Expire, GetLength = p => GetLength(p, Offset, Size) };

            var pks = pc.Parse(pk);

            // 跳过头部长度
            var len = Offset + Math.Abs(Size);
            foreach (var item in pks)
            {
                item.Set(item.Data, item.Offset + len, item.Count - len);
            }

            return pks;
        }

        /// <summary>连接关闭时,清空粘包编码器</summary>
        /// <param name="context"></param>
        /// <param name="reason"></param>
        /// <returns></returns>
        public override Boolean Close(IHandlerContext context, String reason)
        {
            if (context.Owner is IExtend ss) ss["Codec"] = null;

            return base.Close(context, reason);
        }
    }
}