Пример #1
0
        private void AsyncReceive(object state)
        {
            while (true)
            {
                byte[] readBuffer;
                lock (_readBuffers)
                {
                    if (_readBuffers.Count == 0)
                    {
                        lock (_readingMessagesLock)
                        {
                            _readingMessages = false;
                        }
                        return;
                    }

                    readBuffer = _readBuffers.Dequeue();
                }

                _readableDataLen += readBuffer.Length;
                bool process = true;
                while (process)
                {
                    switch (_receiveState)
                    {
                    case ReceiveType.Header:
                    {
                        if (_payloadBuffer == null)
                        {
                            _payloadBuffer = new byte[HEADER_SIZE];
                        }

                        if (_readableDataLen + _writeOffset >= HEADER_SIZE)
                        {
                            // completely received header
                            int headerLength = HEADER_SIZE - _writeOffset;

                            try
                            {
                                Array.Copy(readBuffer, _readOffset, _payloadBuffer, _writeOffset, headerLength);

                                _payloadLen = BitConverter.ToInt32(_payloadBuffer, _readOffset);

                                if (_payloadLen <= 0 || _payloadLen > MAX_MESSAGE_SIZE)
                                {
                                    throw new Exception("invalid header");
                                }

                                // try to re-use old payload buffers which fit
                                if (_payloadBuffer.Length <= _payloadLen + HEADER_SIZE)
                                {
                                    Array.Resize(ref _payloadBuffer, _payloadLen + HEADER_SIZE);
                                }
                            }
                            catch (Exception)
                            {
                                process = false;
                                Disconnect();
                                break;
                            }

                            _readableDataLen -= headerLength;
                            _writeOffset     += headerLength;
                            _readOffset      += headerLength;
                            _receiveState     = ReceiveType.Payload;
                        }
                        else         // _readableDataLen + _writeOffset < HeaderSize
                        {
                            // received only a part of the header
                            try
                            {
                                Array.Copy(readBuffer, _readOffset, _payloadBuffer, _writeOffset, _readableDataLen);
                            }
                            catch (Exception)
                            {
                                process = false;
                                Disconnect();
                                break;
                            }
                            _readOffset  += _readableDataLen;
                            _writeOffset += _readableDataLen;
                            process       = false;
                            // nothing left to process
                        }
                        break;
                    }

                    case ReceiveType.Payload:
                    {
                        int length = (_writeOffset - HEADER_SIZE + _readableDataLen) >= _payloadLen
                                    ? _payloadLen - (_writeOffset - HEADER_SIZE)
                                    : _readableDataLen;

                        try
                        {
                            Array.Copy(readBuffer, _readOffset, _payloadBuffer, _writeOffset, length);
                        }
                        catch (Exception)
                        {
                            process = false;
                            Disconnect();
                            break;
                        }

                        _writeOffset     += length;
                        _readOffset      += length;
                        _readableDataLen -= length;

                        if (_writeOffset - HEADER_SIZE == _payloadLen)
                        {
                            // completely received payload
                            try
                            {
                                using (PayloadReader pr = new PayloadReader(_payloadBuffer, _payloadLen + HEADER_SIZE, false))
                                {
                                    IMessage message = pr.ReadMessage();

                                    OnClientRead(message, _payloadBuffer.Length);
                                }
                            }
                            catch (Exception)
                            {
                                process = false;
                                Disconnect();
                                break;
                            }

                            _receiveState = ReceiveType.Header;
                            _payloadLen   = 0;
                            _writeOffset  = 0;
                        }

                        if (_readableDataLen == 0)
                        {
                            process = false;
                        }

                        break;
                    }
                    }
                }

                _readOffset      = 0;
                _readableDataLen = 0;
            }
        }