public override void FinishRead(SocketChannelAsyncOperation operation) { AbstractSocketByteChannel ch = this.Channel; ch.ResetState(StateFlags.ReadScheduled); IChannelConfiguration config = ch.Configuration; IChannelPipeline pipeline = ch.Pipeline; IByteBufferAllocator allocator = config.Allocator; int maxMessagesPerRead = config.MaxMessagesPerRead; IRecvByteBufAllocatorHandle allocHandle = this.RecvBufAllocHandle; IByteBuffer byteBuf = null; int messages = 0; bool close = false; try { operation.Validate(); int totalReadAmount = 0; bool readPendingReset = false; do { byteBuf = allocHandle.Allocate(allocator); int writable = byteBuf.WritableBytes; int localReadAmount = ch.DoReadBytes(byteBuf); if (localReadAmount <= 0) { // not was read release the buffer byteBuf.Release(); byteBuf = null; close = localReadAmount < 0; break; } if (!readPendingReset) { readPendingReset = true; ch.ReadPending = false; } pipeline.FireChannelRead(byteBuf); byteBuf = null; if (totalReadAmount >= int.MaxValue - localReadAmount) { // Avoid overflow. totalReadAmount = int.MaxValue; break; } totalReadAmount += localReadAmount; // stop reading if (!config.AutoRead) { break; } if (localReadAmount < writable) { // Read less than what the buffer can hold, // which might mean we drained the recv buffer completely. break; } }while (++messages < maxMessagesPerRead); pipeline.FireChannelReadComplete(); allocHandle.Record(totalReadAmount); if (close) { this.CloseOnRead(); close = false; } } catch (Exception t) { this.HandleReadException(pipeline, byteBuf, t, close); } finally { // Check if there is a readPending which was not processed yet. // This could be for two reasons: // /// The user called Channel.read() or ChannelHandlerContext.read() input channelRead(...) method // /// The user called Channel.read() or ChannelHandlerContext.read() input channelReadComplete(...) method // // See https://github.com/netty/netty/issues/2254 if (!close && (ch.ReadPending || config.AutoRead)) { ch.DoBeginRead(); } } }