This post is based on the source code of netty-5.0.0.Alpha5.
Channel
When making a network connection, new instance will be created.
Channel contains:
- IP address and port of destination
- EventLoop instance which serves this channel
- ChannelPipeline instance which stores series of Channelhandler
- function of operations can act on it
Channel.pipeline().fireChannelRead(Buffer) will be called when data is read from network layer.
Reference of Channel may be passed into user logic code, for sending reply first call Channel#isActive to check if that channel is active or not. Then call Channel#write or Channel#writeAndFlush.
ChannelPipeline
When creating a new Channel, a new ChannelPipeline instance is also created. On the fly modification of ChannelHandler in ChannelPipeline without affecting other ChannelPipeline is supported (One of the use cases is to switch to TLS session after an unencrypted session is created in StartTLS protocol).
ChannelHandler(s) which handle application logic are added during ChannelPipeline initialization. To use Bootstrap class as example,
Bootstrap b = new Bootstrap();
b.handler(new ChannelInitializer<DatagramChannel>() {
@Override
protected void initChannel(DatagramChannel ch) {
ChannelPipeline p = ch.pipeline();
p.addLast(new DatagramDnsQueryEncoder())
.addLast(new DatagramDnsResponseDecoder())
.addLast(new SimpleChannelInboundHandler<DatagramDnsResponse>() {
@Override
protected void messageReceived(ChannelHandlerContext ctx, DatagramDnsResponse msg) {
try {
handleQueryResp(msg);
} finally {
ctx.close();
}
}
});
}
});
On ChannelPipeline implementation DefaultChannelPipeline, there is two lists of ChannelHandlerContext.
- handlers: DefaultChannelHandlerContext list, use for instance lookup
- head: first element (always HeadHandler) of DefaultChannelHandlerContext double linked list. First ChannelHandler processing bytes from network layer
- tail: last element (always TailHandler) of DefaultChannelHandlerContext double linked list. First ChannelHandler processing objects from from application
Functions of ChannelHandlers in the chain are run in the same EventExecutor.
ChannelHandler
Code in ChannelHandler can be run in different EventExecutor at the same time. So make sure that the class is thread safe.
A ChannelHandlerContext instance, will be passed as parameter when function of this interface is called. For example
Future<Void> write(ChannelHandlerContext ctx, Object msg);
ChannelHandlerContext contains:
- Channel
- ChannelHandler
- ChannelPipeline
Do not include processing expensive jobs or using blocking functions in any function of ChannelHandler.
When calling Channel#write, message will be go to the beginning of ChannelPipeline. But when calling ChannelHandlerContext#write, message will be go to next ChannelHandler.