目录
实验平台
硬件:银杏科技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. 主函数
c
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相关函数
c
#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。如下图所示:
