Netty decoder Principle Analysis

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 
        }
    }

 

Guess you like

Origin www.cnblogs.com/AllenDuke/p/12622499.html