From both the server-side and client-side perspectives, in the entire Netty framework, one connection corresponds to one Channel. All processing logic for this Channel is within an object called the ChannelPipeline, which is a bidirectional linked list structure. The relationship between the ChannelPipeline and Channel is one-to-one.
Each node in the ChannelPipeline is a ChannelHandlerContext object, which can obtain all contextual information related to the Channel. This object wraps an important object called the ChannelHandler, which is responsible for processing logic.
1. It has two main interfaces: ChannelInboundHandler & ChannelOutBoundHandler
ChannelInboundHandler
- main method: channelRead()
- default implementation: ChannelInboundHandlerAdapter
ChannelOutboundHandler
- main method: write()
- default implementation: ChannelOutboundHandlerAdapter
2. Call order:
Code:
serverBootstrap
.childHandler(new ChannelInitializer<NioSocketChannel>() {
protected void initChannel(NioSocketChannel ch) {
ch.pipeline().addLast(new InBoundHandlerA());
ch.pipeline().addLast(new InBoundHandlerB());
ch.pipeline().addLast(new InBoundHandlerC());
ch.pipeline().addLast(new OutBoundHandlerA());
ch.pipeline().addLast(new OutBoundHandlerB());
ch.pipeline().addLast(new OutBoundHandlerC());
}
});
Graph:
inboundA -> inboundB -> inboundC
outboundA <- outboundB <- outboundC
Console output:
InboundA
InboundB
InboundC
OutboundC
OutboundB
OutboundA
3. Inheritance
-
SimpleChannelInboundHandler extends ChannelInboundHandlerAdapter
-
ChannelInboundHandlerAdapter extends ChannelHandlerAdapter implements ChannelInboundHandler
4. Life cycle of ChannelHandler
public class LifeCyCleTestHandler extends ChannelInboundHandlerAdapter {
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerAdded()");
super.handlerAdded(ctx);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelRegistered()");
super.channelRegistered(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelActive()");
super.channelActive(ctx);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("channelRead()");
super.channelRead(ctx, msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelReadComplete()");
super.channelReadComplete(ctx);
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelInactive()");
super.channelInactive(ctx);
}
@Override
public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
System.out.println("channelUnregistered()");
super.channelUnregistered(ctx);
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerRemoved()");
super.handlerRemoved(ctx);
}
}
handlerAdded() -> channelRegistered() -> channelActive() -> channelRead() -> channelReadComplete()
channelInactive() -> channelUnregistered() -> handlerRemoved()
5. ChannelInitializer
- initChannel()
- both handlerAdded() and channelRegistered() call initChannel()
- initChannel() uses
initMap.add(ctx)
to avoid re-entrance
6. Difference between ctx.writeAndFlush() and ctx.channel().writeAndFlush()
ctx.writeAndFlush()
will ignore all the outBound handlers after it, while ctx.channel().writeAndFlush()
will let the data go through all the handlers including the one after it.
- FixedLengthFrameDecoder
- LineBasedFrameDecoder
- DelimiterBasedFrameDecoder
- LengthFieldBasedFrameDecoder
A codec is a device or computer program that encodes or decodes a data stream or signal. Codec is a portmanteau of coder/decoder.
- strip(): Removes the white space from both, beginning and the end of string
- stripLeading(): Removes the white space from the beginning
- stripTrailing(): Removes the white space from the end
- isBlank(): Indicates if the String is empty or contains only white space characters