Ejemplo n.º 1
0
        /// <summary>
        ///     整个通讯过程中,上次解析正确完成,那么本次解析重新开始
        /// </summary>
        /// <param name="message">指定的字节数据</param>
        /// <param name="vouchers">已解析完成的凭据集合</param>
        protected virtual bool TryFirstParse(ArraySegment <byte> message, ref List <IVoucher> vouchers)
        {
            var _head_ = Field.GetHeadLength();
            var _tail_ = Field.GetTailLength();

            //_lastSegment为Null时,也就是当前数据是新包时
            int i = -1;

            if (Field.BeginChars.Length == 1)
            {
                i = message.IndexOf(Field.BeginChars[0]);
            }
            else
            {
                message.IndexOf(Field.BeginChars); //找到起始字节,丢弃起始字节之前的数据
            }
            if (i < 0)
            {
                //当新包时,找不到起始字符,鬼知道是啥子数据
                if (_Logger.IsInfoEnabled)
                {
                    _Logger.Info($"丢弃整包数据:{message.ToArray().ToHexString(" ")}");
                }
                return(false);
            }

            if (i > 0)
            {
                if (_Logger.IsInfoEnabled)
                {
                    _Logger.Info($"丢弃前导无效数据:{message.Slice(0, i).ToArray().ToHexString(" ")}");
                }
                message = message.Slice(i); //丢弃数据后的数据
            }

            //数据包有几种很不爽的情况,虽然机率很小,但需要处理:头部不全。
            if (message.Count < Field.GetHeadLength())
            {
                //进入半包模式,等待新的数据到来后再处理
                _segment = new VoucherSegment(Field);
                _segment.AppendHead(message);
                return(false);
            }

            _segment = new VoucherSegment(Field);
            _segment.AppendHead(message.Slice(0, _head_));

            _segment.TryGetDataFieldLength(out var dataLength);
            var expect    = _head_ + dataLength + _tail_; //期望的数据包长度
            var tailIndex = _head_ + dataLength;

            if (message.Count < expect) //是个半包,等待下个包到达后拼包完成解析
            {
                if (message.Count < _head_ + dataLength)
                {
                    _segment.AppendData(message.Slice(_head_)); //数据域数量不够
                    return(false);
                }

                _segment.AppendData(message.Slice(_head_, dataLength));
                _segment.AppendTail(message.Slice(tailIndex, message.Count - tailIndex));
                //尾部不全
                return(false);
            }

            _segment.AppendData(message.Slice(_head_, dataLength));
            _segment.AppendTail(message.Slice(tailIndex, _tail_));

            if (message.Count == expect) //哈哈,整整齐齐的一个数据包
            {
                if (!_segment.Verify(SkipCRC))
                {
                    _segment = null;
                    return(false);
                }

                vouchers.Add(_segment.ToVoucher());
                _segment = null;
                return(true);
            }

            if (message.Count > expect) //有粘包,但同时有一个正确的数据包
            {
                if (!_segment.Verify(SkipCRC))
                {
                    _segment = null;
                    var success = TryParse(message.Slice(expect), ref vouchers); //将多出来的数据递归处理
                    return(false | success);
                }

                vouchers.Add(_segment.ToVoucher());
                _segment = null;
                TryParse(message.Slice(expect), ref vouchers); //将多出来的数据递归处理
                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        ///     整个通讯过程中,上次解析的凭据不完整,本次解析接续
        /// </summary>
        /// <param name="message">指定的字节数据</param>
        /// <param name="vouchers">已解析完成的凭据集合</param>
        protected virtual bool TryNextParse(ArraySegment <byte> message, ref List <IVoucher> vouchers)
        {
            var _head_ = Field.GetHeadLength();
            var _tail_ = Field.GetTailLength();

            var currentReadCount = _segment.CountCurrentlyWritten;

            //当未收到完整的头部数据时
            if (currentReadCount < _head_)
            {
                if (message.Count + currentReadCount >= _head_)
                {
                    //当后续的数据补足了头部时
                    //将头部数据补齐,立即处理
                    _segment.AppendHead(message.Slice(0, _head_ - currentReadCount));
                    var again = message.Slice(_head_ - currentReadCount);
                    TryParse(again, ref vouchers);
                }
                else
                {
                    //当后续的包仍然无法补足头部时
                    //将收到的数据置入上包中,等待接收数据
                    _segment.AppendHead(message);
                }

                return(false);
            }

            //当头部正确(已知数据域长度)时。剩余数据域长度。
            _segment.TryGetDataFieldLength(out var dataLength);
            var restDataCount = dataLength - _segment.CountOfDataFieldCurrentlyWritten;
            //当头部正确(已知数据域长度)时。剩余(含尾部)数据长度。上次未收到(未解析)的完整数据包长度。
            var restTotalCount = _head_ + dataLength + _tail_ - _segment.CountCurrentlyWritten;

            //如果本次的数据仍然不满足总长度,将当前的数据填入LastSegment,等待新的数据到来后再处理
            if (message.Count < restTotalCount)
            {
                if (message.Count > restDataCount)
                {
                    //可能包含一部份尾部字符
                    _segment.AppendData(message.Slice(0, restDataCount));
                    _segment.AppendTail(message.Slice(restDataCount));
                }
                else
                {
                    //尾部字符有缺失
                    _segment.AppendData(message);
                }

                return(false);
            }

            //无论是否粘包,本包的主体数据是确认已收到。完成本包的解析过程。
            //粘包与否,后续再进行判断。
            if (restDataCount == 0)
            {
                //上次已将数据域收到完整的数据,只是尾部数据不完整
                var t = _head_ + dataLength + _tail_; //期望的数据包长度
                _segment.AppendTail(message.Slice(0, t - currentReadCount));
            }
            else
            {
                //上次已将数据域收到完整的数据,只是尾部数据不完整
                var p = _head_ + dataLength - currentReadCount;
                _segment.AppendData(message.Slice(0, p));
                _segment.AppendTail(message.Slice(p, _tail_));
            }

            //本包的主体数据解析基本正确,最后一步,CRC校验
            if (_segment.Verify(SkipCRC))
            {
                //当CRC校验通过后,取出相应的数据进行相应的处理
                vouchers.Add(_segment.ToVoucher());
            }

            //如果本次数据大于总长度,即又发生粘包的情况
            if (message.Count > restTotalCount)
            {
                _segment = null;
                //将未解析数据分割出来,做为一个新的事件数据
                TryParse(message.Slice(restTotalCount, message.Count - restTotalCount), ref vouchers);
            }

            _segment = null;
            return(true);
        }