【C/C++】用 C 语言手写 DNS 查询:理解 UDP 和协议报文

用 C 语言手写 DNS 查询:理解 UDP 和协议报文

学习代码:dns/dns.c

在这里插入图片描述

DNS 项目让我第一次比较具体地感受到:网络编程不只是 socketsendtorecvfrom,更重要的是理解协议格式。UDP 本身只负责把一段数据发给对方,至于这段数据里每个字节是什么意思,要由应用层协议决定。DNS 查询就是一个很好的练习,因为它的头部固定,问题区可变,既有结构又不会过分复杂。

项目里定义了 DNS 头部:

struct dns_header
{
    uint16_t id;
    uint16_t flags;
    uint16_t questions;
    uint16_t answer;
    uint16_t authority;
    uint16_t additional;
};

这 12 个字节里,id 用来匹配请求和响应,flags 表示查询标志,questions 表示问题数量。写 DNS 请求时不能只把结构体随便发出去,还要注意网络字节序。多字节字段在网络上传输通常使用大端序,因此构造报文时需要 htons() 之类的转换。

DNS 问题区最有意思的是域名编码。普通字符串是 www.baidu.com,但 DNS 报文里不是直接这样放,而是按“长度 + 内容”的形式编码:

3www5baidu3com0

也就是说,每一段标签前面放一个长度字节,最后用 0 结束。这个格式一开始不直观,但它让解析方不需要扫描点号,只要读长度就知道下一段有多长。

UDP 部分的流程相对直接:

sockfd = socket(AF_INET, SOCK_DGRAM, 0);
sendto(sockfd, request, request_len, 0,
       (struct sockaddr *)&server_addr, sizeof(server_addr));
recvfrom(sockfd, response, sizeof(response), 0, NULL, NULL);

我的理解是,UDP 的“简单”并不等于应用简单。它没有 TCP 的连接管理和可靠传输,所以速度快、开销低,适合 DNS 这种一次请求一次响应的场景。但也正因为它不保证可靠,应用层要能处理超时、丢包、响应解析失败等情况。

这个项目最大的收获是:学习网络协议要从字节层面理解。只会调用 API,遇到问题时容易停在表面;知道报文结构,才能解释为什么一个域名要这样编码,为什么响应里可能有压缩指针,为什么同样是网络通信,DNS 和 HTTP 的处理方式完全不同。

学习链接: https://github.com/0voice

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值