Exemple #1
0
        public async Task ReceiveAsync()
        {
            const int standardBufferLength = 1024 * 4;
            int       currentMessageLength = 0;

            byte[] buffer = ArrayPool <byte> .Shared.Rent(standardBufferLength);

            ReceiveResult?result = null;

            try
            {
                result = await _handler.GetReceiveResult(buffer);

                while (result?.Closed == false)
                {
                    currentMessageLength += result.Read;

                    if (currentMessageLength >= MAX_POOLED_SIZE)
                    {
                        throw new InvalidOperationException("Message too long");
                    }

                    if (result.EndOfMessage)
                    {
                        // process the already filled bytes
                        await ProcessAsync(new ArraySegment <byte>(buffer, 0, currentMessageLength));

                        currentMessageLength = 0; // reset message length

                        // if we grew the buffer too big lets reset it
                        if (buffer.Length > 2 * standardBufferLength)
                        {
                            ArrayPool <byte> .Shared.Return(buffer);

                            buffer = ArrayPool <byte> .Shared.Rent(standardBufferLength);
                        }
                    }
                    else if (buffer.Length - currentMessageLength < standardBufferLength) // there is little room in current buffer
                    {
                        // grow the buffer 4x, but not more than max
                        int newLength = Math.Min(buffer.Length * 4, MAX_POOLED_SIZE);
                        if (newLength > buffer.Length)
                        {
                            byte[] newBuffer = ArrayPool <byte> .Shared.Rent(newLength);

                            buffer.CopyTo(newBuffer, 0);
                            ArrayPool <byte> .Shared.Return(buffer);

                            buffer = newBuffer;
                        }
                    }

                    // receive only new bytes, leave already filled buffer alone
                    result = await _handler.GetReceiveResult(new ArraySegment <byte>(buffer, currentMessageLength, buffer.Length - currentMessageLength));
                }
            }
            finally
            {
                await _handler.CloseAsync(result);

                ArrayPool <byte> .Shared.Return(buffer);
            }
        }