示例#1
0
文件: Message.cs 项目: xlfj5211/esb
        ///// <summary>从流中读取消息</summary>
        ///// <param name="stream">数据流</param>
        ///// <returns></returns>
        //public static Message Read(Stream stream) { return Read(stream, false); }

        /// <summary>从流中读取消息</summary>
        /// <param name="stream">数据流</param>
        /// <param name="rwkind"></param>
        /// <param name="ignoreException">忽略异常。如果忽略异常,读取失败时将返回空,并还原数据流位置</param>
        /// <returns></returns>
        public static Message Read(Stream stream, RWKinds rwkind = RWKinds.Binary, Boolean ignoreException = false)
        {
            if (stream == null || stream.Length - stream.Position < 1)
            {
                return(null);
            }

            //var reader = new BinaryReaderX(stream);
            var reader = RWService.CreateReader(rwkind);

            reader.Stream = stream;
            Set(reader.Settings);

            if (Debug)
            {
                reader.Debug = true;
                reader.EnableTraceStream();
            }

            var start = stream.Position;
            // 消息类型,不同序列化方法的识别方式不同
            MessageKind   kind   = (MessageKind)0;
            Type          type   = null;
            MessageHeader header = null;

            if (rwkind == RWKinds.Binary)
            {
                // 检查第一个字节
                //var ch = reader.Reader.PeekChar();
                var ch = stream.ReadByte();
                if (ch < 0)
                {
                    return(null);
                }
                stream.Seek(-1, SeekOrigin.Current);

                var first = (Byte)ch;

                #region 消息头部扩展
                // 第一个字节的最高位决定是否扩展
                if (MessageHeader.IsValid(first))
                {
                    try
                    {
                        header = new MessageHeader();
                        header.Read(reader.Stream);
                    }
                    catch
                    {
                        stream.Position = start;
                        return(null);
                    }

                    // 如果使用了消息头,判断一下数据流长度是否满足
                    if (header.HasFlag(MessageHeader.Flags.Length) && header.Length > stream.Length - stream.Position)
                    {
                        stream.Position = start;
                        return(null);
                    }
                }
                #endregion

                // 读取了响应类型和消息类型后,动态创建消息对象
                kind = (MessageKind)(reader.ReadByte() & 0x7F);
            }
            else
            {
                // 前面的数字表示消息种类
                var  sb = new StringBuilder();
                Char c;
                while (true)
                {
                    c = (Char)stream.ReadByte();
                    if (c < '0' || c > '9')
                    {
                        break;
                    }
                    sb.Append(c);
                }
                // 多读了一个,退回去
                stream.Seek(-1, SeekOrigin.Current);
                kind = (MessageKind)Convert.ToByte(sb.ToString());

                //var s = stream.IndexOf(new Byte[] { (Byte)'<' });
                //if (s >= 0)
                //{
                //    var e = stream.IndexOf(new Byte[] { (Byte)'>' }, s + 1);
                //    if (e >= 0)
                //    {
                //        stream.Position = s;
                //        var msgName = Encoding.UTF8.GetString(stream.ReadBytes(e - s - 1));
                //        if (!String.IsNullOrEmpty(msgName) && !msgName.Contains(" ")) type = TypeX.GetType(msgName);
                //    }
                //}
                //var settings = new XmlReaderSettings();
                //settings.IgnoreWhitespace = true;
                //settings.IgnoreComments = true;
                //var xr = XmlReader.Create(stream, settings);
                //while (xr.NodeType != XmlNodeType.Element) { if (!xr.Read())break; }

                //stream.Position = start;
            }

            #region 识别消息类型
            if (type == null)
            {
                type = ObjectContainer.Current.ResolveType <Message>(kind);
            }
            if (type == null)
            {
                if (ignoreException)
                {
                    stream.Position = start;
                    return(null);
                }
                else
                {
                    throw new XException("无法识别的消息类型(Kind={0})!", kind);
                }
            }
            #endregion

            #region 读取消息
            Message msg;
            if (stream.Position == stream.Length)
            {
                msg = TypeX.CreateInstance(type, null) as Message;
            }
            else
            {
                try
                {
                    msg = reader.ReadObject(type) as Message;
                    if (msg == null)
                    {
                        throw new XException("数据格式不正确!");
                    }
                }
                catch (Exception ex)
                {
                    if (ignoreException)
                    {
                        stream.Position = start;
                        return(null);
                    }

                    var em = ex.Message;
                    if (DumpStreamWhenError)
                    {
                        stream.Position = start;
                        var bin = String.Format("{0:yyyy_MM_dd_HHmmss_fff}.msg", DateTime.Now);
                        bin = Path.Combine(XTrace.LogPath, bin);
                        if (!Path.IsPathRooted(bin))
                        {
                            bin = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, bin);
                        }
                        bin = Path.GetFullPath(bin);
                        var dir = Path.GetDirectoryName(bin);
                        if (!Directory.Exists(dir))
                        {
                            Directory.CreateDirectory(dir);
                        }
                        File.WriteAllBytes(bin, stream.ReadBytes());
                        em = String.Format("已Dump数据流到{0}。{1}", bin, em);
                    }
                    var ex2 = new XException("无法从数据流中读取{0}(Kind={1})消息!{2}", type.Name, kind, em);
                    throw ex2;
                }
            }
            msg.Header = header;
            return(msg);

            #endregion
        }
示例#2
0
文件: Message.cs 项目: xlfj5211/esb
        /// <summary>通过首字节和扩展头的Length判断数据流是否消息。</summary>
        /// <remarks>
        /// 首字节作为Kind,然后查找是否有消息注册该Kind。
        /// 对于大小写,一般要求使用扩展头的Length。
        /// </remarks>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static Boolean IsMessage(Stream stream)
        {
            //return PeekType(stream) != null;
            var p = stream.Position;

            try
            {
                // 第一个字节很重要
                var n = stream.ReadByte();
                if (n < 0)
                {
                    return(false);
                }
                var first = (Byte)n;

                // 如果没用消息头
                if (!MessageHeader.IsValid(first))
                {
                    // 查一下该消息类型是否以注册,如果未注册,直接返回false
                    var type = ObjectContainer.Current.ResolveType <Message>((MessageKind)(first & 0x7F));
                    if (type == null)
                    {
                        return(false);
                    }
                }

                try
                {
                    stream.Position = p;
                    var header = new MessageHeader();
                    header.Read(stream);

                    // 如果使用了消息头,判断一下数据流长度是否满足
                    if (header.HasFlag(MessageHeader.Flags.Length) && header.Length > stream.Length - stream.Position)
                    {
                        return(false);
                    }
                }
                catch
                {
                    // 如果连消息头都读取不了,显然不对
                    return(false);
                }

                // 重新判断一下至粗恶类型
                {
                    n = stream.ReadByte();
                    if (n < 0)
                    {
                        return(false);
                    }
                    first = (Byte)n;
                    // 查一下该消息类型是否以注册,如果未注册,直接返回false
                    var type = ObjectContainer.Current.ResolveType <Message>((MessageKind)(first & 0x7F));
                    if (type == null)
                    {
                        return(false);
                    }
                }

                return(true);
            }
            finally
            {
                stream.Position = p;
            }
        }
示例#3
0
        /// <summary>拆分数据流为多个消息</summary>
        /// <param name="stream"></param>
        /// <param name="size"></param>
        /// <param name="header"></param>
        public void Split(Stream stream, Int32 size, MessageHeader header = null)
        {
            // 组包消息全部采用消息头长度,这里估算,方便内部预留大小,如果包大小刚好在边界上,可能会浪费一个字节空间,不过这个可能性很小
            if (header == null)
            {
                header = new MessageHeader();
            }
            header.Length = size;

            // 消息头大小
            var headerLength = 0;

            if (header != null)
            {
                headerLength = header.ToArray().Length;
            }

            // 先估算数据包个数
            var count = (Int32)Math.Ceiling((Double)(stream.Length - stream.Position) / (size - (1 + 4 * 3 + 1) - headerLength));

            // 估计组消息头部长度,最大化构造包。
            // Kind + 消息头
            var len = 1 + headerLength;

            // Identity
            len += GetBytesCount(Identity);
            // Count
            len += 1;

            // 加上数据包大小。因为压缩整数的存在,这里不是绝对准确,但是大多数时候不会有问题
            len += GetBytesCount(size);
            // !!!不要忘了数据部分的对象引用
            len += 1;

            // 计算数据部分大小
            var index = Items.Count;

            while (stream.Position < stream.Length)
            {
                var msg = new GroupMessage();
                msg.Header   = header.Clone();
                msg.Identity = Identity;
                msg.Index    = ++index;
                //msg.Count = count;

                // 加上索引长度,计算真正的头部长度
                var trueLen = len + GetBytesCount(msg.Index);
                // 第一个元素采用精确Count
                if (msg.Index == 1)
                {
                    trueLen += GetBytesCount(count) - 1;
                }

                var len2 = stream.Length - stream.Position;
                if (len2 > size - trueLen)
                {
                    len2 = size - trueLen;
                }
                //var buffer = new Byte[len2];
                //stream.Read(buffer, 0, buffer.Length);
                //msg.Data = buffer;
                msg.Data = stream.ReadBytes(len2);

                // 减去Header以外的全部长度
                msg.Header.Length = (Int32)(trueLen + len2) - headerLength;

                // 最后一个修正长度,因为数据量可能很少,前面的GetBytesCount(size)可能不对。
                if (len2 < size - trueLen)
                {
                    msg.Header.Length += GetBytesCount(len2) - GetBytesCount(size);
                }

                lock (Items)
                {
                    Items.Add(msg);
                }
            }

            //if (Items.Count > 0) Items[0].Count = Items.Count;
            // 第一个组消息的Count是准确的,总数Count小于128的全部使用实际总数Count,其它都是用0
            count = Items.Count;
            var isLittle = count < 128;

            foreach (var item in Items)
            {
                item.Count = isLittle ? count : 0;
            }
            if (count > 0)
            {
                Items[0].Count = count;
            }

            Total = count;
        }