QUESTION,ANSWER,AUTHORITY,ADDITIONAL;每个section里面又包含了多个DnsRecord, DnsRecord代表的就是Resource record,简称为RR , RR中有一个CLASS字段 , 下面是DnsRecord中CLASS字段的定义:
int CLASS_IN = 1;int CLASS_CSNET = 2;int CLASS_CHAOS = 3;int CLASS_HESIOD = 4;int CLASS_NONE = 254;int CLASS_ANY = 255;DnsMessage是DNS消息的统一表示 , 对于查询来说 , netty中提供了一个专门的查询类叫做DefaultDnsQuery 。
先来看下DefaultDnsQuery的定义和构造函数:
public class DefaultDnsQuery extends AbstractDnsMessage implements DnsQuery {public DefaultDnsQuery(int id) {super(id);}public DefaultDnsQuery(int id, DnsOpCode opCode) {super(id, opCode);}DefaultDnsQuery的构造函数需要传入id和opCode 。
我们可以这样定义一个DNS查询:
int randomID = (int) (System.currentTimeMillis() / 1000);DnsQuery query = new DefaultDnsQuery(randomID, DnsOpCode.QUERY)既然是QEURY,那么还需要设置4个sections中的查询section:
query.setRecord(DnsSection.QUESTION, new DefaultDnsQuestion(queryDomain, DnsRecordType.A));这里调用的是setRecord方法向section中插入RR数据 。
这里的RR数据使用的是DefaultDnsQuestion 。DefaultDnsQuestion的构造函数有两个 , 一个是要查询的domain name , 这里就是”www.flydean.com”,另外一个参数是dns记录的类型 。
dns记录的类型有很多种 , 在netty中有一个专门的类DnsRecordType表示,DnsRecordType中定义了很多个类型 , 如下所示:
public class DnsRecordType implements Comparable<DnsRecordType> {public static final DnsRecordType A = new DnsRecordType(1, "A");public static final DnsRecordType NS = new DnsRecordType(2, "NS");public static final DnsRecordType CNAME = new DnsRecordType(5, "CNAME");public static final DnsRecordType SOA = new DnsRecordType(6, "SOA");public static final DnsRecordType PTR = new DnsRecordType(12, "PTR");public static final DnsRecordType MX = new DnsRecordType(15, "MX");public static final DnsRecordType TXT = new DnsRecordType(16, "TXT");...因为类型比较多 , 我们挑选几个常用的进行讲解 。
- A类型 , 是address的缩写 , 用来指定主机名或者域名对应的ip地址.
- NS类型 , 是name server的缩写 , 是域名服务器记录 , 用来指定域名由哪个DNS服务器来进行解析 。
- MX类型,是mail exchanger的缩写 , 是一个邮件交换记录 , 用来根据邮箱的后缀来定位邮件服务器 。
- CNAME类型 , 是canonical name的缩写 , 可以将多个名字映射到同一个主机.
- TXT类型 , 用来表示主机或者域名的说明信息 。
这里我们选择使用A , 用来查询域名对应的主机IP地址 。
构建好query之后 , 我们就可以使用netty client发送query指令到dns服务器了 , 具体的代码如下:
DnsQuery query = new DefaultDnsQuery(randomID, DnsOpCode.QUERY).setRecord(DnsSection.QUESTION, new DefaultDnsQuestion(queryDomain, DnsRecordType.A));ch.writeAndFlush(query).sync();DNS查询的消息处理DNS的查询消息我们已经发送出去了 , 接下来就是对消息的处理和解析了 。还记得我们自定义的Do53ChannelInitializer吗?看一下它的实现:
class Do53ChannelInitializer extends ChannelInitializer<SocketChannel> {@Overrideprotected void initChannel(SocketChannel ch) {ChannelPipeline p = ch.pipeline();p.addLast(new TcpDnsQueryEncoder()).addLast(new TcpDnsResponseDecoder()).addLast(new Do53ChannelInboundHandler());}}我们向pipline中添加了两个netty自带的编码解码器TcpDnsQueryEncoder和TcpDnsResponseDecoder , 还有一个自定义用来做消息解析的Do53ChannelInboundHandler 。因为我们向channel中写入的是DnsQuery,所以需要一个encoder将DnsQuery编码为ByteBuf,这里使用的是netty提供的TcpDnsQueryEncoder:
public final class TcpDnsQueryEncoder extends MessageToByteEncoder<DnsQuery> TcpDnsQueryEncoder继承自MessageToByteEncoder , 表示将DnsQuery编码为ByteBuf 。看下他的encode方法:
protected void encode(ChannelHandlerContext ctx, DnsQuery msg, ByteBuf out) throws Exception {out.writerIndex(out.writerIndex() + 2);this.encoder.encode(msg, out);out.setShort(0, out.readableBytes() - 2);}可以看到TcpDnsQueryEncoder在msg编码之前存储了msg的长度信息 , 所以是一个基于长度的对象编码器 。
推荐阅读
- 阿里3个小时手把手教你用zookeeper实现分布式锁
- 2021年取消非师范考教资-2021年非师范不能考教师编制-2021年非师范考教资后成绩保留多久
- 设置路由器wifi上网方法教程 192.168.0.1 登陆页面
- 教练:驾考新规定要不断停车 女子科目三考试把安全员开吐了
- 狗十三反映的家庭教育,狗十三讲什么-
- 虹鳟鱼做法教程 清蒸虹鳟鱼的做法
- 招聘|“47人面试,竟有35人缺考”,县城教师招聘,出现多人中途放弃!
- 第一学历是什么意思?
- 营养师教你几个小诀窍管住你的贪吃嘴
- 丰胸秘籍三部曲教你减肥不减胸
