io.netty5.example.dns.udp.DnsClient is DNS client to lookup A record of domain "www.example.com" by UDP.
Setup io.netty5.channel.Channel instance
Please read the following code.
EventLoopGroup group = new MultithreadEventLoopGroup(NioHandler.newFactory())
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioDatagramChannel.class)
.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();
}
}
});
}
});
- anything related to communication is executed in one of the threads of EventLoopGroup
- NioDatagramChannel.class states that the underlying network library is Java NIO DatagramChannel
- handler() accepts a subclass of io.netty5.channel.ChannelInitializer which implements the function initChannel(DatagramChannel). It is to setup list of ChannelHandler in ChannelPipeline. I called this class setup channel class
Channel instances will be built and obtained in the following.
final Channel ch = b.bind(0).asStage().get();
When bind(0) is called, io.netty5.bootstrap.Bootstrap#init is triggered.
@Override
Future<Channel> init(Channel channel) {
ChannelPipeline p = channel.pipeline();
setChannelOptions(channel, newOptionsArray(), logger);
setAttributes(channel, newAttributesArray());
p.addLast(config.handler());
return channel.executor().newSucceededFuture(channel);
}
Value of config.handler() is setup channel class. And then io.netty5.channel.ChannelInitializer#handlerAdded is triggered.
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
try {
initChannel((C) ctx.channel());
} catch (Throwable cause) {
// Explicitly call exceptionCaught(...) as we removed the handler before calling initChannel(...).
// We do so to prevent multiple calls to initChannel(...).
channelExceptionCaught(ctx, cause);
} finally {
if (!ctx.isRemoved()) {
ctx.pipeline().remove(this);
}
}
}
Setup channel class will be removed after ChannelPipeline is setup. Then the following will be in ChannelPipeline
- DefaultChannelPipeline$HeadHandler
- DatagramDnsQueryEncoder
- DatagramDnsResponseDecoder
- subclass of SimpleChannelInboundHandler
- DefaultChannelPipeline$TailHandler