手把手教你使用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);

推薦閱讀