手把手教你使用netty搭建一个DNS tcp服务器( 二 )

decode接受一个ByteBuf对象,首先调用LengthFieldBasedFrameDecoder的decode方法,将真正需要解析的内容解析出来,然后再调用DnsMessageUtil的decodeDnsQuery方法将真正的ByteBuf内容解码成为DnsQuery返回 。
这样就可以在自定义的handler中处理DnsQuery消息了 。
上面代码中,自定义的handler叫做Do53ServerInboundHandler:
class Do53ServerInboundHandler extends SimpleChannelInboundHandler<DnsQuery>从定义看 , Do53ServerInboundHandler要处理的消息就是DnsQuery 。
看一下它的channelRead0方法:
    protected void channelRead0(ChannelHandlerContext ctx,                                DnsQuery msg) throws Exception {        DnsQuestion question = msg.recordAt(DnsSection.QUESTION);        log.info("Query is: {}", question);        ctx.writeAndFlush(newResponse(msg, question, 1000, QUERY_RESULT));    }我们从DnsQuery的QUESTION section中拿到DnsQuestion,然后解析DnsQuestion的内容,根据DnsQuestion的内容返回一个response给客户端 。
这里的respone是我们自定义的:
    private DefaultDnsResponse newResponse(DnsQuery query,                                           DnsQuestion question,                                           long ttl, byte[]... addresses) {        DefaultDnsResponse response = new DefaultDnsResponse(query.id());        response.addRecord(DnsSection.QUESTION, question);        for (byte[] address : addresses) {            DefaultDnsRawRecord queryAnswer = new DefaultDnsRawRecord(                    question.name(),                    DnsRecordType.A, ttl, Unpooled.wrappedBuffer(address));            response.addRecord(DnsSection.ANSWER, queryAnswer);        }        return response;    }上面的代码封装了一个新的DefaultDnsResponse对象,并使用query的id作为DefaultDnsResponse的id 。并将question作为response的QUESEION section 。
除了QUESTION section,response中还需要ANSWER section,这个ANSWER section需要填充一个DnsRecord 。
这里构造了一个DefaultDnsRawRecord,传入了record的name,type , ttl和具体内容 。
最后将构建好的DefaultDnsResponse返回 。
因为客户端查询的是A address,按道理我们需要通过QUESTION中传入的domain名字,然后根据DNS服务器中存储的记录进行查找,最终返回对应域名的IP地址 。
但是因为我们只是模拟的DNS服务器,所以并没有真实的域名IP记录,所以这里我们伪造了一个ip地址:
    private static final byte[] QUERY_RESULT = new byte[]{46, 53, 107, 110};然后调用Unpooled的wrappedBuffer方法,将byte数组转换成为ByteBuf,传入DefaultDnsRawRecord的构造函数中 。
这样我们的DNS服务器就搭建好了 。
DNS客户端消息请求上面我们搭建好了DNS服务器 , 接下来就可以使用DNS客户端来请求DNS服务器了 。
这里我们使用之前创建好的netty DNS客户端,只不过进行少许改动 , 将DNS服务器的域名和IP地址替换成下面的值:
        Do53TcpClient client = new Do53TcpClient();        final String dnsServer = "127.0.0.1";        final int dnsPort = 53;        final String queryDomain ="www.flydean.com";        client.startDnsClient(dnsServer,dnsPort,queryDomain);

推荐阅读