STM32H743-ARM例程36-DNS

目录

实验平台

硬件:银杏科技GT7000双核心开发板-ARM-STM32H743XIH6,银杏科技iToolXE仿真器

软件:最新版本STM32CubeH7固件库STM32CubeMX v6.10.0,开发板环境MDK v5.35TCP&UDP测试工具,串口工具putty

网盘资料包:链接: https://pan.baidu.com/s/1Y3nwaY4SMxfoUsdqPm2R3w?pwd=inba 提取码: inba

DNS 简介

DNS 的全称是 域名系统。可以把它想象成 互联网的电话簿。

在互联网上,所有的设备(如服务器、电脑、手机)都是通过一串数字来找到彼此的,这串数字叫做 IP 地址(例如 192.0.2.1 或 2001:db8::8a2e:370:7334)。然而,对人类来说,记住这些数字串非常困难,而记住像 google.combaidu.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。如下图所示:

相关推荐
工具人55556 小时前
电脑插入USB一个端口都识别不出来
单片机·嵌入式硬件·电脑
KOAN凯擎小妹7 小时前
晶振信号质量:上升下降时间与占空比
单片机·嵌入式硬件·fpga开发·信息与通信
czy87874757 小时前
C语言实现策略模式
c语言·排序算法·策略模式
不觉晚秋8 小时前
极限挑战之一命速通哈夫曼树
c语言·数据结构··哈夫曼树
散峰而望8 小时前
Dev-C++一些问题的处理
c语言·开发语言·数据库·c++·编辑器
sheepwjl8 小时前
《嵌入式硬件(二十一):基于IMX6ULL的脉冲宽度调制(PWM)操作》
嵌入式硬件·pwm·脉冲宽度调制
时间不说谎8 小时前
C语言 strtok线程不安全
c语言
第七序章8 小时前
【C + +】C++11 (下) | 类新功能 + STL 变化 + 包装器全解析
c语言·数据结构·c++·人工智能·哈希算法·1024程序员节
小莞尔9 小时前
【51单片机】【protues仿真】基于51单片机简易电子琴系统(8键)
c语言·单片机·嵌入式硬件·物联网·51单片机