Fixed-length decoder, for example, clarify the context.
NioEventLoop,run
@Override protected void run() { int selectCnt = 0; for (;;) { //..... else if (strategy > 0) { Final long ioStartTime = System.nanoTime (); try { processSelectedKeys (); // Channel occurrence of an event handling } the finally { // Ensure® Always WE RUN Tasks. Final Long IOTime to System.nanoTime = () - ioStartTime; ranTasks = runAllTasks (ioTime * ( 100 - ioRatio) / ioRatio); } } } }
NioEventLoop,processSelectedKeys
private void processSelectedKeys() { if (selectedKeys != null) { processSelectedKeysOptimized(); } else { processSelectedKeysPlain(selector.selectedKeys()); } }
NioEventLoop,processSelectedKeysOptimized
private void processSelectedKeysOptimized() { for (int i = 0; i < selectedKeys.size; ++i) {//循环处理keys final SelectionKey k = selectedKeys.keys[i]; // null out entry in the array to allow to have it GC'ed once the Channel close // See https://github.com/netty/netty/issues/2363 selectedKeys.keys[i] = null;//帮助GC final Object a = k.attachment(); if (a instanceof AbstractNioChannel) { processSelectedKey (K, (AbstractNioChannel) A); // process Channel }
// ...
} }
NioEventLoop,processSelectedKey
private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) { final AbstractNioChannel.NioUnsafe unsafe = ch.unsafe();try { if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { unsafe.read (); // process the read event, the data is read from nio channel } } }
AbstractNioByteChannel,read
@Override public Final void the Read () { // read the data buffer in a cycle which is to deal with this at the time of the buffer data, there are data arrives, without waiting for the next time the SELECT the try { do { byteBuf = allocHandle.allocate(allocator); allocHandle.lastBytesRead (doReadBytes (byteBuf)); // read the data from the channel to byteBuf // ... pipeline.fireChannelRead (byteBuf); // back propagation byteBuf, entered chain byteBuf = null ; } while (allocHandle.continueReading()); } }
DefaultChannelPipeline,fireChannelRead
@Override public final ChannelPipeline fireChannelRead(Object msg) { AbstractChannelHandlerContext.invokeChannelRead (head, msg); // from the head of a doubly linked list to start return the this ; }
AbstractChannelHandlerContext,invokeChannelRead
static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) { final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next); Executor EventExecutor = next.executor (); IF (executor.inEventLoop ()) { // if the current thread is the thread directly read netty io next.invokeChannelRead (m); } else { Executor.execute ( new new the Runnable () { // otherwise packaged into tasks, the task added to the queue @Override public void RUN () { next.invokeChannelRead(m); } }); } }
Private void invokeChannelRead (Object msg) { IF (InvokeHandler ()) { // If the current handlerContext the handler can call the try { ((ChannelInboundHandler) handler()).channelRead(this, msg); } catch (Throwable t) { notifyHandlerException(t); } } else { fireChannelRead(msg); } }
ByteToMessageDecoder, channelRead, began to focus on analysis
ByteBuf cumulation; // not the last buffer processed semi package information
@Override public void channelRead (ChannelHandlerContext CTX, Object msg) throws Exception { IF (msg the instanceof ByteBuf) { // If msg is passed in a ByteBuf, then the it decodes CodecOutputList CodecOutputList.newInstance oUT = (); // objects with a list of parsed to load the try { first = cumulation == null; /** * Todo If the last half a packet of information and the unprocessed, then the accumulation of new information processing */ cumulation = cumulator.cumulate(ctx.alloc(), first ? Unpooled.EMPTY_BUFFER : cumulation, (ByteBuf) msg); callDecode (CTX, cumulation, OUT); // for msg decoding (decoded information spread), may still be half a pack, will accumulate in the half-package cumulation } the catch (DecoderException E) { the throw E; } catch (Exception e) { throw new DecoderException(e); } The finally { IF (cumulation =! Null && cumulation.isReadable ()!) { // If the reading is (full-decoded), then the release half the packet buffer numReads = 0 ; cumulation.release(); cumulation = null; } else if (++ numReads >= discardAfterReads) {//如果可以抛弃一些字节 // We did enough reads already try to discard some bytes so we not risk to see a OOME. // See https://github.com/netty/netty/issues/4275 numReads = 0; discardSomeReadBytes(); } int size = out.size(); firedChannelRead |= out.insertSinceRecycled(); fireChannelRead (CTX, OUT, size); // back propagation OUT, if fixed-length decoder, in callDecode has completed propagation, this time = 0 size out.recycle (); // empty array } } The else { // Otherwise back propagation ctx.fireChannelRead (msg); } }
ByteToMessageDecoder, fireChannelRead, passed to the next HandlerContext
static void fireChannelRead(ChannelHandlerContext ctx, CodecOutputList msgs, int numElements) { for (int i = 0; i < numElements; i ++) { ctx.fireChannelRead (msgs.getUnsafe (I)); // the outputList data one by one in the back propagation } }
ByteToMessageDecode, callDecode
protected void callDecode (ChannelHandlerContext CTX, in ByteBuf, List <Object> OUT) { the try { the while (in.isReadable ()) { // for parsing out the cycle time ByteBuf int outsize = out.size ();
// if outList there data directly to back propagation, the fixed length decoder, each seems to be a decoded after the object will be added to the decoded out in, i.e., each cycle will be spread out backward, out of the only one
IF (outsize> 0) { fireChannelRead (CTX, OUT, outsize); out.clear (); // all at once and then pass on empty IF (ctx.isRemoved ()) { BREAK ; } outSize = 0; } int oldInputLength in.readableBytes = (); // number of bytes before the decoding-readable recording / ** * This particular calls as fixed length decoder in the decoder decode method, * Once a decoding method in such as 8-byte, if less than 8 bytes is not read in from the inside. * Read half packet analysis processing */ decodeRemovalReentryProtection(ctx, in, out);
}
}
}
ByteToMessageDecode,decodeRemovalReentryProtection
final void decodeRemovalReentryProtection(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { decodeState = STATE_CALLING_CHILD_DECODE; the try { // decoding, will resolve to the object into the inside out. Abstract method, such as call decode fixed length decoder (), a decoding target inside out into the decode (ctx, in, out) ; } finally { boolean removePending = decodeState == STATE_HANDLER_REMOVED_PENDING; decodeState = STATE_INIT; IF (removePending) { // if the current to be handlerContext remove, then immediately back propagation fireChannelRead (ctx, out, out.size ( )); out.clear(); handlerRemoved(ctx); } } }
FixedLengthFrameDecoder, decode
@Override protected final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception { Object decoded = decode(ctx, in); if (decoded != null) { out.add (Decoded); // read out after one frame applied to the inside } }
protected Object decode( @SuppressWarnings ( "UnusedParameters") ChannelHandlerContext CTX, ByteBuf in) throws Exception { IF (in.readableBytes () <frameLength) { // If not a frame, it returns null return null ; } The else { return in.readRetainedSlice (frameLength); // read out a frame } }