DNS域名解析
1. 域名解析过程
从用户输入一个网址到网页最终展现到用户面前,中间究竟发生了什么?下面两张图展示了其大致的流程:
域名的分层结构如下图所示,想要使用DNS域名解析功能,必须要知道域名服务器地址(一般配置为路由器地址)
2. DNS应用实例
以下实例完成的功能为:利用 gethostbyname() 函数,通过网址(www.baidu.com)找到相对应的IP地址
//netdb.h
/** @ingroup netdbapi */
#define gethostbyname(name) lwip_gethostbyname(name)
struct hostent *lwip_gethostbyname(const char *name);
struct hostent {
char *h_name; /* 正式主机名 */
char **h_aliases; /* 主机别名*/
int h_addrtype; /* 主机IP地址类型 */
int h_length; /* 主机IP地址字节长度*/
char **h_addr_list; /* 主机的IP地址列表*/
};
- 参考Socket API编程优化一文,在该文的工程源码基础上进行修改
- DNS宏开关:将opt.h文件中的LWIP_DNS宏定义开启
//opt.h文件中
/**
* LWIP_DNS==1: Turn on DNS module.
*/
#if !defined LWIP_DNS || defined __DOXYGEN__
#define LWIP_DNS 1
#endif
- 配置DNS服务器:在dns.c文件中手动添加DNS服务器地址
//dns.c文件中手动添加DNS服务器地址
/** DNS server IP address */
#ifndef DNS_SERVER_ADDRESS
extern ip4_addr_t gw; //网关地址
#define DNS_SERVER_ADDRESS(ipaddr) (memcpy(ipaddr, &gw, sizeof(ip4_addr_t)))
#endif
- 文件lwip.c修改代码:STM32CubeMX生成的MX_LWIP_init()函数中tcpip_init()的初始化在ip地址初始化之前,这里应该调整到IP地址初始化之后
注意:以下网关地址要填充到DNS_SERVER_ADDRESS地址中,注意要与所连路由器的网关地址一致
/* IP addresses initialization */
IP_ADDRESS[0] = 192;
IP_ADDRESS[1] = 168;
IP_ADDRESS[2] = 1;
IP_ADDRESS[3] = 10;
NETMASK_ADDRESS[0] = 255;
NETMASK_ADDRESS[1] = 255;
NETMASK_ADDRESS[2] = 255;
NETMASK_ADDRESS[3] = 0;
GATEWAY_ADDRESS[0] = 192;
GATEWAY_ADDRESS[1] = 168;
GATEWAY_ADDRESS[2] = 1;
GATEWAY_ADDRESS[3] = 1;
/* IP addresses initialization without DHCP (IPv4) */
IP4_ADDR(&ipaddr, IP_ADDRESS[0], IP_ADDRESS[1], IP_ADDRESS[2], IP_ADDRESS[3]);
IP4_ADDR(&netmask, NETMASK_ADDRESS[0], NETMASK_ADDRESS[1] , NETMASK_ADDRESS[2], NETMASK_ADDRESS[3]);
IP4_ADDR(&gw, GATEWAY_ADDRESS[0], GATEWAY_ADDRESS[1], GATEWAY_ADDRESS[2], GATEWAY_ADDRESS[3]);
/* Initilialize the LwIP stack with RTOS */
tcpip_init( NULL, NULL ); //调整到IP地址初始化之后
- 在工程中创建dns_client.c和对应的头文件
#include "dns_client.h"
#include "ctype.h"
#include "FreeRTOS.h"
#include "task.h"
#include "netdb.h"
void vDnsClientTask(void){
int i;
struct sockaddr_in server_addr;
//dns 域名解析功能
struct hostent *p_hostent = NULL;
p_hostent = gethostbyname("www.makeru.com.cn");
if(p_hostent){
for(i = 0; p_hostent->h_addr_list[i]; i++){
printf("host ip:%s\r\n", inet_ntoa(*p_hostent->h_addr_list[i]));
}
}else{
printf("get host ip fail!\r\n");
}
}
- 在freertos.c文件中的默认任务里面添加代码
void StartDefaultTask(void const * argument){
/* init code for LWIP */
MX_LWIP_Init();
/* USER CODE BEGIN StartDefaultTask */
printf("DNS client test!\r\n");
/* Infinite loop */
for(;;){
vDnsClientTask();
osDelay(100);
}
/* USER CODE END StartDefaultTask */
}
- 编译无误下载到开发板,用网线将开发板与路由器相连。打开串口助手可以看到串口返回得到的IP地址;使用ping命令可以ping通该地址;将该IP地址输入到浏览器中可以访问百度网站