/// <summary>
        /// Shallow copies this message with shallow copied frames.
        /// </summary>
        /// <returns>Shallow copied message.</returns>
        public MqMessage ShallowCopy()
        {
            var message = new MqMessage();

            foreach (var frame in _frames)
            {
                message.Add(frame.ShallowCopy());
            }

            return(message);
        }
        /// <summary>
        /// Deep copies this message with deep copied frames.
        /// </summary>
        /// <returns>Deep copied message.</returns>
        public MqMessage Clone()
        {
            var message = new MqMessage();

            foreach (var frame in _frames)
            {
                message.Add(frame.Clone());
            }

            return(message);
        }
        /// <summary>
        /// Internal method called by the Postmaster on a different thread to process all bytes in the inbox.
        /// </summary>
        /// <returns>True if incoming queue was processed; False if nothing was available for process.</returns>
        private void ProcessIncomingQueue()
        {
            if (_processMessage == null)
            {
                _processMessage = new MqMessage();
            }

            Queue <MqMessage> messages = null;

            byte[] buffer;
            while (_inboxBytes.TryDequeue(out buffer))
            {
                try
                {
                    _frameBuilder.Write(buffer, 0, buffer.Length);
                }
                catch (InvalidDataException)
                {
                    //logger.Error(ex, "Connector {0}: Client send invalid data.", Connection.Id);

                    Close(SocketCloseReason.ProtocolError);
                    break;
                }

                var frameCount = _frameBuilder.Frames.Count;
                //logger.Debug("Connector {0}: Parsed {1} frames.", Connection.Id, frame_count);

                for (var i = 0; i < frameCount; i++)
                {
                    var frame = _frameBuilder.Frames.Dequeue();

                    // Do nothing if this is a ping frame.
                    if (frame.FrameType == MqFrameType.Ping)
                    {
                        if (BaseSocket.Mode == SocketMode.Server)
                        {
                            // Re-send ping frame back to the client to refresh client connection timeout timer.
                            Send(CreateFrame(null, MqFrameType.Ping));
                        }
                        continue;
                    }

                    // Determine if this frame is a command type.  If it is, process it and don't add it to the message.
                    if (frame.FrameType == MqFrameType.Command)
                    {
                        ProcessCommand(frame);
                        continue;
                    }

                    _processMessage.Add(frame);

                    if (frame.FrameType != MqFrameType.EmptyLast && frame.FrameType != MqFrameType.Last)
                    {
                        continue;
                    }

                    if (messages == null)
                    {
                        messages = new Queue <MqMessage>();
                    }

                    messages.Enqueue(_processMessage);
                    _processMessage = new MqMessage();
                }
            }

            if (messages == null)
            {
                return;
            }


            OnIncomingMessage(this, new IncomingMessageEventArgs <TSession, TConfig>(messages, (TSession)this));

            lock (_inboxLock)
            {
                if (_inboxBytes.IsEmpty == false)
                {
                    _inboxTask = Task.Run((Action)ProcessIncomingQueue);
                }
            }
        }