必须填写至少10个字的日志
nnhy authored at 2012-07-27 18:48:21
5.11 KiB
X
using System;
using System.IO;
using NewLife.Serialization;

namespace NewLife.Messaging
{
    /// <summary>消息头</summary>
    /// <remarks>
    /// 消息头结构:
    /// 1字节标识
    /// 1字节通道
    /// 4字节会话
    /// </remarks>
    public class MessageHeader
    {
        #region 属性
        private Flags _Flag;
        /// <summary>标识位</summary>
        public Flags Flag { get { return _Flag; } set { _Flag = value; } }

        /// <summary>是否采用消息头</summary>
        public Boolean UseHeader { get { return HasFlag(Flags.Header); } set { SetFlag(Flags.Header, value); } }

        private Byte _Channel;
        /// <summary>消息通道</summary>
        public Byte Channel { get { return _Channel; } set { _Channel = value; SetFlag(Flags.Channel, value != 0); } }

        private Int32 _SessionID;
        /// <summary>会话编号</summary>
        public Int32 SessionID { get { return _SessionID; } set { _SessionID = value; SetFlag(Flags.SessionID, value != 0); } }

        private Int32 _Length;
        /// <summary>消息长度,消息头以外的长度,也不包括Kind。建议在较长消息中指定消息体长度,便于接收方处理粘包的问题。</summary>
        public Int32 Length { get { return _Length; } set { _Length = value; SetFlag(Flags.Length, value != 0); } }
        #endregion

        #region 读写
        /// <summary>把消息头写入到流中</summary>
        /// <param name="stream"></param>
        public void Write(Stream stream)
        {
            if (!UseHeader) return;

            var writer = new BinaryWriterX(stream);
            writer.Settings.EncodeInt = true;
            writer.Write((Byte)Flag);
            if (HasFlag(Flags.Channel)) writer.Write(Channel);
            if (HasFlag(Flags.SessionID)) writer.Write(SessionID);
            if (HasFlag(Flags.Length)) writer.Write(Length);
        }

        /// <summary>把消息头转为字节数组</summary>
        /// <returns></returns>
        public Byte[] ToArray()
        {
            if (!UseHeader) return new Byte[0];

            var ms = new MemoryStream();
            Write(ms);
            return ms.ToArray();
        }

        /// <summary>从数据流中读取消息头</summary>
        /// <param name="stream"></param>
        public void Read(Stream stream)
        {
            var reader = new BinaryReaderX(stream);
            reader.Settings.EncodeInt = true;
            Flag = (Flags)reader.ReadByte();
            if (HasFlag(Flags.Channel)) Channel = reader.ReadByte();
            if (HasFlag(Flags.SessionID)) SessionID = reader.ReadInt32();
            if (HasFlag(Flags.Length)) Length = reader.ReadInt32();
        }
        #endregion

        #region 方法
        ///// <summary>计算指定类型消息头所需要的长度</summary>
        ///// <param name="flag"></param>
        ///// <returns></returns>
        //public static Int32 GetSize(Flags flag)
        //{
        //    // 第一个字节Flag
        //    var n = 1;
        //    if (HasFlag(Flags.Channel)) n++;
        //    if (HasFlag(Flags.SessionID)) n += 4;
        //}

        /// <summary>克隆</summary>
        /// <returns></returns>
        public MessageHeader Clone()
        {
            return this.MemberwiseClone() as MessageHeader;
        }
        #endregion

        #region 标识
        /// <summary>读取标识位</summary>
        /// <param name="flag"></param>
        /// <returns></returns>
        public Boolean HasFlag(Flags flag) { return Flag.Has(flag); }

        /// <summary>设置标识位</summary>
        /// <param name="flag"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public MessageHeader SetFlag(Flags flag, Boolean value)
        {
            if (flag != Flags.Header)
            {
                // 设置任意标识,会启用头。取消所有标识,会禁用头
                if (value)
                {
                    Flag = Flag.Set(Flags.Header, true);
                }
                else
                {
                    if ((Byte)flag == 0) Flag = Flag.Set(Flags.Header, false);
                }
            }

            Flag = Flag.Set(flag, value);
            return this;
        }

        /// <summary>是否有效消息头</summary>
        /// <param name="bit"></param>
        /// <returns></returns>
        public static Boolean IsValid(Byte bit) { return ((Flags)bit).Has(Flags.Header); }
        #endregion

        #region 枚举
        /// <summary>用于指定消息头采用那些字段的标识</summary>
        [Flags]
        public enum Flags : byte
        {
            /// <summary>是否使用消息头</summary>
            Header = 0x80,

            /// <summary>是否使用通道</summary>
            Channel = 2,

            /// <summary>是否使用会话</summary>
            SessionID = 4,

            /// <summary>是否使用长度</summary>
            Length = 8
        }
        #endregion
    }
}