STM32H743-ARM例程36-DNS
目录
- 实验平台
 - DNS 简介
 - DNS工作流程
 - 总结
 
- STM32CubeMX生成工程
 - 实验代码
 - 实验现象
 
实验平台
硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器
 软件:最新版本STM32CubeH7固件库,STM32CubeMX v6.10.0,开发板环境MDK v5.35,TCP&UDP测试工具,串口工具putty
 网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba
DNS 简介
  DNS 的全称是 域名系统。可以把它想象成 互联网的电话簿。
   在互联网上,所有的设备(如服务器、电脑、手机)都是通过一串数字来找到彼此的,这串数字叫做 IP 地址(例如 192.0.2.1 或 2001:db8::8a2e:370:7334)。然而,对人类来说,记住这些数字串非常困难,而记住像 google.com 或 baidu.com 这样的名字就容易得多。
   DNS 的核心功能就是在这两者之间进行翻译:将人类易于记忆的域名转换为机器能够识别的 IP 地址。
   一个简单的比喻:电话簿
   域名:就像一个人的 名字(例如,“张三”)。
   IP 地址:就像这个人的 电话号码(例如,138-XXXX-XXXX)。
   DNS:就像你手机里的 通讯录。当你想给“张三”打电话时,你不需要记住他的号码,只需要在通讯录里找到他的名字,手机就会自动帮你拨通对应的号码。
   同样地,当您在浏览器中输入 www.google.com 时,DNS 系统就会在背后忙碌起来,帮你找到 www.google.com 对应的真实 IP 地址,然后您的浏览器才能连接到该网站。
DNS工作流程
  在浏览器中输入一个网址并按下回车时,DNS 解析过程通常在毫秒内完成,它涉及以下四个关键步骤:
 1.DNS 解析器
- 通常由您的互联网服务提供商(如电信、联通)提供,也可以是自己设置的公共 DNS(如 114.114.114.114 或 8.8.8.8)。
 - 它是整个查询过程的“协调员”。它接收来自您电脑的查询请求,并负责向其他服务器追问答案。
 
2.根域名服务器
-  
全球只有13组(注意是组,不是台,每组都有很多镜像服务器)根服务器。
 -  
它不直接知道 www.google.com 的 IP,但它知道哪些服务器负责管理 .com 这样的顶级域。它会告诉解析器:“你去问负责 .com 的服务器吧。”
 
3.顶级域域名服务器
-  
负责管理特定的顶级域,如 .com、.org、.net 或国家顶级域如 .cn、.uk。
 -  
它收到解析器的查询后,会说:“google.com 这个域名是由另一组权威服务器管理的,这是它们的地址,你去问它们。”
 
4.权威域名服务器
-  
这是最终答案的持有者。每个域名都会在它的注册商那里设置一组权威服务器。
 -  
当解析器找到它时,它会准确地返回 www.google.com 对应的 IP 地址。
 
完整流程总结:
 电脑 → 解析器 → 根服务器 → .com TLD 服务器 → google.com 的权威服务器 → 获取到 IP 地址 → 返回给解析器 → 解析器返回给您的电脑 → 浏览器通过 IP 地址连接网站。
总结
DNS 是互联网的基石,是一个庞大、分布式、层级式的数据库系统。它默默地在后台工作,将我们输入的友好网址转换成计算机能够理解的地址,是我们能够轻松畅游互联网的关键所在。没有 DNS,今天的互联网将无法正常运转。
STM32CubeMX生成工程
我们参考前面章节STM32H743-结合CubeMX新建HAL库MDK工程,打开CubeMX软件,重复步骤不再展示。我们来看配置MPU配置、以太网部分和Lwip部分配置如下图所示:
 配置以太网。选用RMII(精简的独立于介质接口)模式
 
 
 
 
 MPU配置
 
 LWIP配置
 
 
实验代码
1. 主函数
void My_Dns_callback(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{sprintf( (char *)TimeBuff,"%s ip is:%s\r\n",name,ip4addr_ntoa(ipaddr));if( tcp_echoserver_pcb ){if( (es->state == ES_ACCEPTED) || (es->state == ES_RECEIVED ) ){/* allocate pbuf */es->p = pbuf_alloc(PBUF_TRANSPORT, strlen((char*)TimeBuff), PBUF_POOL);if (es->p){/* copy data to pbuf */pbuf_take(es->p, (char*)TimeBuff, strlen((char*)TimeBuff));tcp_echoserver_send(tcp_echoserver_pcb, es );}}}}
/* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int i = 0;
char buffer[UART_BUFFER_SIZE];
/* USER CODE END 0 *//*** @brief  The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 */uint8_t first = 1;/* USER CODE END 1 *//* MPU Configuration--------------------------------------------------------*/MPU_Config();
/* Enable the CPU Cache *//* Enable I-Cache---------------------------------------------------------*/SCB_EnableICache();/* Enable D-Cache---------------------------------------------------------*/SCB_EnableDCache();/* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_LWIP_Init();MX_USART6_UART_Init(); tcp_echoserver_init();/* USER CODE BEGIN 2 */uart6.initialize(115200);uart6.printf("\x0c");uart6.printf("GT7000 OK!\r\n");HAL_GPIO_WritePin(PHYAD0_GPIO_Port,PHYAD0_Pin,GPIO_PIN_RESET);    uart6.printf("initialize OK!\r\n");/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){MX_LWIP_Process();if( gnetif.ip_addr.addr && first && HAL_GetTick() > 1000 ){first = 0;dns_gethostbyname("www.baidu.com", &DestIPaddr, My_Dns_callback, NULL );}if(uart6.receive_ok_flag == 1){uart6.receive_ok_flag = 0;memset(buffer,0,20);memcpy(buffer,uart6.receive_buffer,20);     for(i = 0;i < 20;i ++){buffer[i] = tolower(buffer[i]);}           if(memcmp(buffer,"dns",strlen("dns")) == 0){                uart6.printf("\r\n%s\r\n",(char*)TimeBuff);     }else if(memcpy(buffer,"clear",strlen("clear")) == 0){uart6.printf("\x0c");           }else{uart6.printf("\r\nCommand not found!\r\n");}}/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
} 
2.DHCP相关函数
#include "eth_udp.h"
#include <string.h>
#include "dhcp.h"
#include "uart6.h"
//--------------------- Function Prototype ----------------------//   
void initialize(void);
void receive_data(void *arg,struct udp_pcb *upcb,struct pbuf *p,const ip_addr_t *addr,u16_t port);
void send_data(struct udp_pcb *upcb);
void connection_close(struct udp_pcb *upcb);
void udp_client_send(struct udp_pcb *upcb, char *pData);
void lwip_dhcp_task(void);
//--------------------------- Variable --------------------------// 
ETH_UDP_T eth_udp = {.initialize = initialize,.receive_data = receive_data,.send_data = send_data,.connection_close = connection_close,.receive_ok_flag = 0
};__lwip_dev lwipdev;
uint8_t PCIP_ADDRESS[4] = {192, 168, 31, 220};
extern struct netif gnetif;void initialize(void)
{err_t err;struct ip4_addr rmtipaddr;eth_udp.udppcb = udp_new();//创建一个新的UDP协议控制块IP4_ADDR(&rmtipaddr ,PCIP_ADDRESS[0] ,PCIP_ADDRESS[1] ,PCIP_ADDRESS[2] ,PCIP_ADDRESS[3]);//设置服务器(PC)IP地址udp_connect(eth_udp.udppcb ,&rmtipaddr,REMOTE_PORT);							//连接至远程客户端if (eth_udp.udppcb){err = udp_bind(eth_udp.udppcb ,IP_ADDR_ANY ,LOCAL_PORT);						//给UDP协议控制块绑定端口号和IP地址if(err == ERR_OK){udp_recv(eth_udp.udppcb ,eth_udp.receive_data ,NULL);				//设置接收回调函数}else{udp_remove(eth_udp.udppcb);}}
}static void receive_data(void *arg,struct udp_pcb *upcb,struct pbuf *p,const ip_addr_t *addr,u16_t port)
{uint32_t data_len = 0;struct pbuf *q;if(p!=NULL){memset(eth_udp.receive_buffer,0,EHT_BUFFER_SIZE);for(q=p;q!=NULL;q=q->next){if(q->len > (EHT_BUFFER_SIZE-data_len)) memcpy(eth_udp.receive_buffer + data_len,q->payload,(EHT_BUFFER_SIZE - data_len));else memcpy(eth_udp.receive_buffer+data_len,q->payload,q->len);data_len += q->len;  	if(data_len > EHT_BUFFER_SIZE) break;}eth_udp.receive_ok_flag = 1;pbuf_free(p);}else{udp_disconnect(upcb); } 
} void send_data(struct udp_pcb *upcb)
{struct pbuf *ptr;memcpy(eth_udp.send_buffer,eth_udp.receive_buffer,1024);ptr=pbuf_alloc(PBUF_TRANSPORT,strlen((char*)eth_udp.send_buffer),PBUF_RAM); 	//申请内存if(ptr){pbuf_take(ptr,(char *)eth_udp.send_buffer,strlen((char*)eth_udp.send_buffer));	//拷贝数据udp_send(upcb,ptr);															//发送数据pbuf_free(ptr);																//释放内存}
} void connection_close(struct udp_pcb *upcb)
{udp_disconnect(upcb); udp_remove(upcb);
}void lwip_dhcp_task(void)
{uint32_t ip=0,netmask=0,gw=0;lwipdev.dhcpstatus=0;	//正在DHCP	uart6.printf("正在获取地址...\r\n");ip=gnetif.ip_addr.addr;		//读取新IP地址netmask=gnetif.netmask.addr;//读取子网掩码gw=gnetif.gw.addr;			//读取默认网关 if(ip!=0)   					//当正确读取到IP地址的时候{//flag = 1;lwipdev.dhcpstatus=2;	//DHCP成功uart6.printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",\lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);//解析出通过DHCP获取到的IP地址lwipdev.ip[3]=(uint8_t)(ip>>24); lwipdev.ip[2]=(uint8_t)(ip>>16);lwipdev.ip[1]=(uint8_t)(ip>>8); lwipdev.ip[0]=(uint8_t)(ip);uart6.printf("通过DHCP获取到IP地址..............%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);//解析通过DHCP获取到的子网掩码地址lwipdev.netmask[3]=(uint8_t)(netmask>>24);lwipdev.netmask[2]=(uint8_t)(netmask>>16);lwipdev.netmask[1]=(uint8_t)(netmask>>8);lwipdev.netmask[0]=(uint8_t)(netmask);uart6.printf("通过DHCP获取到子网掩码............%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);//解析出通过DHCP获取到的默认网关lwipdev.gateway[3]=(uint8_t)(gw>>24);lwipdev.gateway[2]=(uint8_t)(gw>>16);lwipdev.gateway[1]=(uint8_t)(gw>>8);lwipdev.gateway[0]=(uint8_t)(gw);uart6.printf("通过DHCP获取到的默认网关..........%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);}else if(netif_dhcp_data(&gnetif)->tries >  LWIP_MAX_DHCP_TRIES) //通过DHCP服务获取IP地址失败,且超过最大尝试次数netif_dhcp_data(gnetif)  (netif)->client_data[(id)]{lwipdev.dhcpstatus=0XFF;//DHCP失败.//使用静态IP地址IP4_ADDR(&(gnetif.ip_addr),lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);IP4_ADDR(&(gnetif.netmask),lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);IP4_ADDR(&(gnetif.gw),lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);printf("DHCP服务超时,使用静态IP地址!\r\n");printf("网卡en的MAC地址为:................%d.%d.%d.%d.%d.%d\r\n",lwipdev.mac[0],lwipdev.mac[1],lwipdev.mac[2],lwipdev.mac[3],lwipdev.mac[4],lwipdev.mac[5]);printf("静态IP地址........................%d.%d.%d.%d\r\n",lwipdev.ip[0],lwipdev.ip[1],lwipdev.ip[2],lwipdev.ip[3]);printf("子网掩码..........................%d.%d.%d.%d\r\n",lwipdev.netmask[0],lwipdev.netmask[1],lwipdev.netmask[2],lwipdev.netmask[3]);printf("默认网关..........................%d.%d.%d.%d\r\n",lwipdev.gateway[0],lwipdev.gateway[1],lwipdev.gateway[2],lwipdev.gateway[3]);}
} 
实验现象
  本实验例程采用的 LWIP 版本位 2.1.2,其中包含了 DHCP 协议,在对 LWIP 的 DHCP功能进行使能和启动后,即可通过路由器对设备进行 IP 地址的分配。
   我们需要一根网线将GT7000的网口与路由器的网口连接,然后运行程序在putty串口工具输入“dns”解析出百度域名(www.baidu.com)的 IP 地址为 116.155.0.36。如下图所示:
   
