Netty Pipeline and those things ChannelHandler

Pipeline and ChannelHandler Netty is an important part of the process flow, a traffic processor corresponds to a ChannelHandler, is responsible Pipeline ChannelHandler string together each "container", the processing flow is completed combine them together Netty.

Pipeline

Each channel will hold a ChannelPipeline internal objects pipeline, pipeline internal DefaultChannelPipeline default implementation maintains a list DefaultChannelHandlerContext.

channel read and write operations will come DefaultChannelPipeline, when the channel is completed register, active, when read, readComplete other operations, the pipeline will trigger a corresponding method.

  1. When the channel registered to the selector, trigger fireChannelRegistered method of pipeline;
  2. When the channel is available, triggering fireChannelActive method of pipeline. (FireChannelActive trigger is usually triggered after fireChannelRegistered);
  3. When a client sends data, trigger fireChannelRead method of pipeline;
  4. It will trigger fireChannelReadComplete method pipeline after triggering fireChannelRead method of pipeline.

DefaultChannelPipelineNetty default pipeline is achieved, the corresponding code is as follows:

public class DefaultChannelPipeline implements ChannelPipeline {
    // head和tail是handler的处理链/上下文
    final AbstractChannelHandlerContext head;
    final AbstractChannelHandlerContext tail;
    private final Channel channel;
     
    protected DefaultChannelPipeline(Channel channel) {
        this.channel = ObjectUtil.checkNotNull(channel, "channel");
        succeededFuture = new SucceededChannelFuture(channel, null);
        voidPromise =  new VoidChannelPromise(channel, true);
  
        tail = new TailContext(this);
        head = new HeadContext(this);
        head.next = tail;
        tail.prev = head;
    }
}

TailContext ChannelOutboundHandler implements the interface, HeadContext ChannelOutboundHandler interfaces and implements ChannelInboundHandler, head, and tail form a linked list.

For Inbound operation, processing is started from the head backward traversal; OutBound for operation, the processing starts from tail, the forward traversal. So what is Inbound operation which is OutBound does it work?

  • InBound:channelRegistered、channelActive、channelRead、channelReadComplete;
  • OutBound:bind、connect、close、flush等。

Note, HeadContext achieved ChannelInboundHandlerand ChannelOutboundHandlerinterfaces for OutBound operation, the last will come HeadContext to deal with, in fact, just a shallow TailContext package, the actual logic is not much. HeadContext contains a socket netty underlying operating category for the bind/connect/disconnect/close/deregister/beginRead/read/wirte/flushoperation objects are accomplished by the unsafe.

final class HeadContext extends AbstractChannelHandlerContext
        implements ChannelOutboundHandler, ChannelInboundHandler {
 
    // netty的底层socket操作类
    private final Unsafe unsafe;
 
    HeadContext(DefaultChannelPipeline pipeline) {
        super(pipeline, null, HEAD_NAME, false, true);
        unsafe = pipeline.channel().unsafe();
        setAddComplete();
    }
    // ...
}

The list is embodied channelPipeline channelHandlerContext "chain of responsibility" mode, the processing of a request may involve a plurality ChannelHandler, such decodeHandler, custom business ChannelHandler and encodeHandler. Business channelHandler example:

public class EchoHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        ByteBuf in = (ByteBuf) msg;
        System.out.println(in.toString(CharsetUtil.UTF_8));
        ctx.write(msg);
    }
    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        ctx.flush();
    }
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

Call channelReadComplete method flush, in fact, will come head.flush method, the final call unsafe.flush will send out the data. netty pipeline is the responsibility chain (or pipelined) reflect mode by pipeline mechanism, the netty data processing mechanism has powerful scalability and flexibility.

ChannelHandler

The channel is ChannelHandler netty processor, based on the service processing netty, no matter how complex, are made to do ChannelHandler, may involve multiple channelHandler, channelHandler several types: encoder, decoder, and other business processes.

decoderHandler

After converting the received data decoderHandler mostly or processing, basically subclass ByteToMessageDecoder which class diagram is as follows:

ByteToMessageDecoder there will be a temporary data storage buffer, if the received data is incomplete, you can wait until the next staging process the next time the data is received.

encoderHandler

encoderHandler mostly converted into bytebuf message data, basically subclass MessageToByteEncoder which class diagram is as follows:

Business channelHandler

Business is business logic processing channelHanler a user-defined, usually at the last to addLast to channel.pipeline, such as http processing logic is as follows:

ServerBootstrap boot = new ServerBootstrap();
boot.group(bossGroup, workerGroup)
    .channel(NioServerSocketChannel.class)
    .localAddress(8080)
    .childHandler(new ChannelInitializer<SocketChannel>() {
        @Override
        protected void initChannel(SocketChannel ch) throws Exception {
            ch.pipeline()
                    .addLast("decoder", new HttpRequestDecoder())
                    .addLast("encoder", new HttpResponseEncoder())
                    .addLast("aggregator", new HttpObjectAggregator(512 * 1024))
                    .addLast("handler", new HttpHandler());
        }
    });

The DefaultChannelPipeline headContext (ChannelOutboundHandler achieved and ChannelInboundHandler), tailContext (realized ChannelOutboundHandler) and self-defined ChannelHandler (decoderHandler, ecoderHandler, channelHandler the like, typically implemented ChannelInboundHandler), by linking ChannelHandlerContext, formed a request processing chain.

Notice how the order ChannelOutboundHandler and ChannelInboundHandler added, in fact, just remember one: between ChannelOutboundHandler order to ensure, among ChannelInboundHandler to ensure order, without having to guarantee the order between the two.

channelHandler的运行流程图:

TailContesxt本身代码不多并且挺多方法都是"空实现",不过它的channelRead方法内部会执行ReferenceCountUtil.release(msg)释放msg占用的内存空间,也就是说在未定义用户ChannelHandler或者用户ChannelHandler的channelRead继续传递后续ChannelHandler的channelRead时,到TailContext的channelRead时会自动释放msg所占用内存。

推荐阅读

欢迎小伙伴关注【TopCoder】阅读更多精彩好文。

Guess you like

Origin www.cnblogs.com/luoxn28/p/11963736.html