/// <summary>
        /// Continue receiving body
        /// </summary>
        public void ContinueReceivingBody(byte[] buffer, int offset, int length)
        {
            //NOTE::
            //need to call this method many times until all body receive complete

            _toBeReceiveData = new SocketReceiveState(buffer, offset, length);
            beginReceiveData(_toBeReceiveData);
        }
        /// <summary>
        /// receive data callback
        /// </summary>
        /// <param name="result"></param>
        private void receiveDataCallback(IAsyncResult result)
        {
            SocketReceiveState receiveState = (SocketReceiveState)result.AsyncState;
            int recByte = 0;

            try
            {
                recByte              = _workingSocket.EndReceive(result);
                receiveState.Offset += recByte;

                if (!_isReceivingHeader)
                {
                    _receivingProgress.Completed += recByte;
                }
            }
            catch (Exception ex)
            {
                onClose(ex);
                return;
            }

            if (recByte > 0)
            {
                try
                {
                    analyzeData(receiveState);
                }
                catch (Exception ex)
                {
                    onClose(ex);
                    return;
                }
            }
            else
            {
                onClose(new AsyncSocketException("Connection has been closed"));
            }
        }
        /// <summary>
        /// Begin receive data
        /// </summary>
        /// <param name="header"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public void Receive(IProtocolHeader header, byte[] buffer, int offset, int length)
        {
            //the buffer length must large than TRANSFER_BLOCK_LENGTH
            if (buffer.Length - offset < TRANSFER_BLOCK_LENGTH ||
                length < TRANSFER_BLOCK_LENGTH)
            {
                throw new ArgumentException("Buffer length must large than TRANSFER_BLOCK_LENGTH");
            }

            if (_isClosing)
            {
                throw new AsyncSocketException("Connection has closed");
            }

            _lastReceiveHeader = header;
            _toBeReceiveData   = new SocketReceiveState(buffer, offset, length);
            _receivingProgress.Reset();

            SocketReceiveState receiveState = new SocketReceiveState(
                _headerBuffer, 0, _headerBuffer.Length);

            beginReceiveData(receiveState);
        }
        /// <summary>
        /// begin receive data
        /// </summary>
        private void beginReceiveData(SocketReceiveState receiveState)
        {
            try
            {
                //calculate the length need to be receive at this time
                int receiveByte = receiveState.Length - (receiveState.Offset - receiveState.StartIndex);
                if (receiveByte > TRANSFER_BLOCK_LENGTH)
                {
                    receiveByte = TRANSFER_BLOCK_LENGTH;
                }

                _workingSocket.BeginReceive(
                    receiveState.Data,
                    receiveState.Offset,
                    receiveByte,
                    SocketFlags.None,
                    new AsyncCallback(receiveDataCallback),
                    receiveState);
            }
            catch (Exception ex)
            {
                onClose(ex);
            }
        }
        /// <summary>
        /// analyze the received data
        /// </summary>
        /// <param name="receiveState"></param>
        private void analyzeData(SocketReceiveState receiveState)
        {
            //a flag to indicate whether the header/body has received complete
            bool receiveCompleted = true;

            if (_isReceivingHeader)
            {
                //seek the split-symbol between the header and body
                int position = seekSplitSymbolPosition(receiveState.Data, receiveState.Offset);

                if (position < 0)
                {
                    //continue receive header
                    receiveCompleted = false;
                    if (receiveState.Offset >= HEADER_BUFFER_LENGTH)
                    {
                        onClose(new AsyncSocketException("Header data overflow"));
                        return;
                    }
                }
                else
                {
                    //parse the header string
                    //byte[] headerData = new byte[position];
                    //Buffer.BlockCopy(receiveState.Data, 0, headerData, 0, headerData.Length);
                    //_lastReceiveHeader.HeaderRawData = headerData;

                    _lastReceiveHeader.SetHeaderRawData(receiveState.Data, 0, position);

                    //raise ReceiveHeaderComplete event
                    ReceiveHeaderCompleteEventArgs arg = new ReceiveHeaderCompleteEventArgs(_lastReceiveHeader);

                    try
                    {
                        ReceiveHeaderComplete(this, arg);
                        //NOTE::
                        //here, caller must specify the "arg.TotalPlanReceivingLength" value,
                        //to indicate whether continue receive body or not
                    }
                    catch (Exception ex)
                    {
                        onClose(ex);
                        return;
                    }

                    if (arg.TotalPlanReceivingLength > 0)
                    {
                        //need receive body
                        _isReceivingHeader       = false;
                        _receivingProgress.Total = arg.TotalPlanReceivingLength;

                        //check this data whether it contains partial body
                        int tailLength = receiveState.Offset - position - 4;
                        if (tailLength > 0)
                        {
                            Buffer.BlockCopy(receiveState.Data, position + 4,
                                             _toBeReceiveData.Data, _toBeReceiveData.Offset, tailLength);

                            _toBeReceiveData.Offset     += tailLength;
                            _receivingProgress.Completed = tailLength;
                        }

                        //replace the receive state object
                        receiveState = _toBeReceiveData;
                    }
                }
            }

            //to judge if the body has receive complete
            if (!_isReceivingHeader)
            {
                if (receiveState.Offset - receiveState.StartIndex < receiveState.Length &&
                    _receivingProgress.Completed < _receivingProgress.Total)
                {
                    //not complete yet
                    receiveCompleted = false;
                }
                else
                {
                    //receive body complete

                    if (_receivingProgress.Completed >= _receivingProgress.Total)
                    {
                        //all body receive complete, reset this flag
                        _isReceivingHeader = true;
                    }

                    //raise the ReceiveBodyComplete event
                    ReceiveBodyCompleteEventArgs arg = new ReceiveBodyCompleteEventArgs(
                        _lastReceiveHeader,
                        receiveState.Data,
                        receiveState.Offset,
                        receiveState.StartIndex,
                        _receivingProgress.Completed,
                        _receivingProgress.Total);

                    try
                    {
                        ReceiveBodyComplete(this, arg);
                    }
                    catch (Exception ex)
                    {
                        onClose(ex);
                        return;
                    }
                }
            }

            //continue to receiving header or body data
            if (!receiveCompleted)
            {
                beginReceiveData(receiveState);
            }
        }