栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

【ESP32-S3的开发】| 3.ESP32S3 设置DNS、静态IP实现域名解析

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【ESP32-S3的开发】| 3.ESP32S3 设置DNS、静态IP实现域名解析

【ESP32-S3的开发】

第三章 设置DNS、静态IP实现域名解析

【ESP32-S3的开发】前言一、关闭DHCP,设置DNS、网关、子网掩码、静态IP

1.关闭DHCP2.设置 IP 的主要函数3.设置 DNS3.设置 网关、子网掩码、静态IP 二、域名解析API

1.getaddrinfo2.完整的示例代码 总结


前言

其实这个和 ESP 系列关系不大了,目前 ESP32 大部分都支持,我也就把文章定位在这个系列上吧!
在讲述ESP32S3设置DNS、静态IP,实现域名解析前,先了解一下域名解析的相关概念

通俗理解~主机名、IP、域名、端口、DNS服务器
https://www.cnblogs.com/juggdxy/p/7193598.html

DNS解析的工作原理
https://blog.csdn.net/zhengqijun_/article/details/53811229

子网掩码和ip地址的关系(理解如何通过子网掩码和 IP 地址得到网络地址和主机名)
https://www.html.cn/qa/other/21879.html

DHCP概念
https://blog.csdn.net/m0_37836194/article/details/98721097

可能会有人提出这么个疑问,DHCP自动获得服务器分配的lP地址和子网掩码不就可以了吗?为毛要设置另外的DNS、网关和静态IP,甚至是端口?
这里面介绍一种场景:公司的主机使用运营商的DNS,直接连接外网,但公司因为需要限制某部分IP的访问,对访问外网的出口做了部分限制,这时候设置了公司自己的DNS,其他主机通过公司的服务器连接外网时,就都能被管控了。在一些信息管控比较严格的地方会有这种情况出现,如果设备需要部署在这些地方时,对方只开放部分静态IP给设备,用以连接,从而让设备接受监管,这时候就需要设备设置DNS、静态IP等操作了


一、关闭DHCP,设置DNS、网关、子网掩码、静态IP

需要添加的头文件

#include "lwip/dns.h"
#include "lwip/err.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
1.关闭DHCP
tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA); //在 Station 接口上停止 DHCP 客户端
2.设置 IP 的主要函数
IP4_ADDR(ipaddr, a,b,c,d)

为了简便解析以及配置,这边封装一个解析函数,匹配所有和 IP 设置相关的操作, 用户习惯性传入诸如:192.168.1.1 这种字符格式的参数,这里根据这种格式,解析并进行设置,当然,最终启用并且生效的函数仍然是上面讲到的 IP4_ADDR

void SetDNS_GW_STATICIP(ip4_addr_t *ip4_usr_addr, char *ip4_str)
{
    char iptemp[4];
    uint8_t ip[4];
    char *ptemp1 = ip4_str, *ptemp2;
    uint8_t i = 0, comma_num = 0;
    while (ip4_str[i] != '')
    {
        if (ip4_str[i] == '.')
        {
            comma_num++;
        }
        i++;
    }
    if (comma_num == 3)
    {
        for (i = 0; i < comma_num; i++)
        {
            ptemp2 = ptemp1;
            ptemp1 = strchr(ptemp1, '.');
            memset(iptemp, 0, sizeof(iptemp));
            strncpy(iptemp, ptemp2, strlen(ptemp2) - strlen(ptemp1));
            ip[i] = atoi(iptemp);
            ptemp1 += 1;
        }
        memset(iptemp, 0, sizeof(iptemp));
        strncpy(iptemp, ptemp1, strlen(ptemp1));
        ip[i] = atoi(iptemp);
        IP4_ADDR(ip4_usr_addr, ip[0], ip[1], ip[2], ip[3]);
    }
}
3.设置 DNS
typedef struct __dns_gw_staticip
{
    char dns_ipaddr[16];
    char gw_ipaddr[16];
    char staticip_ipaddr[16];
    char netmask_ipaddr[16];
} dns_gw_static_st;

dns_gw_static_st NetRec_NetAddrConfigData = {0};

memset(NetRec_NetAddrConfigData.dns_ipaddr, 0, sizeof(NetRec_NetAddrConfigData.dns_ipaddr));
memcpy(NetRec_NetAddrConfigData.dns_ipaddr, "192.168.100.16", strlen("192.168.100.16"));

tcpip_adapter_dns_info_t dns_info = {0};
SetDNS_GW_STATICIP((ip4_addr_t *)(&dns_info.ip), NetRec_NetAddrConfigData.dns_ipaddr);

ESP_ERROR_CHECK(tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_DNS_FALLBACK, &dns_info));

上面用到的 tcpip_adapter_dns_info_t 结构体来源于 esp-idf/components/tcpid_adapter/include 路径下的头文件

3.设置 网关、子网掩码、静态IP
tcpip_adapter_ip_info_t ip_info = {0};
//具体IP、掩码、网关是多少大家自己视情况而定
SetDNS_GW_STATICIP(&ip_info.ip, NetRec_NetAddrConfigData.staticip_ipaddr);
SetDNS_GW_STATICIP(&ip_info.gw, NetRec_NetAddrConfigData.gw_ipaddr);
SetDNS_GW_STATICIP(&ip_info.netmask, NetRec_NetAddrConfigData.netmask_ipaddr);

ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
二、域名解析API 1.getaddrinfo

指定域名、端口号,根据指定返回协议的协议簇、返回地址的类型,创建出域名解析的结果,并被 result 指向,可以通过 result 协议簇解析得到 域名对应的 IP 地址和端口号

int getaddrinfo( const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result );
2.完整的示例代码
#include "esp_event_loop.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "nvs_flash.h"
#include 

#include "lwip/dns.h"
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"


#define ENABLE_STATIC_IP 1

#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY


static EventGroupHandle_t s_wifi_event_group;


const int WIFI_CONNECTED_BIT = BIT0;

static const char *TAG = "wifi station";

static int s_retry_num = 0;
const struct addrinfo hints = {
    .ai_family = AF_INET, 
    .ai_socktype = SOCK_STREAM, 
};
uint32_t ipv4_cnt;
int error;
ip_addr_t getIP = {0};
bool bDNSFound = 0;

static esp_err_t event_handler(void *ctx, system_event_t *event)
{
    switch (event->event_id)
    {
        case SYSTEM_EVENT_STA_START:
            esp_wifi_connect();
            break;
        case SYSTEM_EVENT_STA_GOT_IP:
            ESP_LOGI(TAG, "got ip:%s", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip));
            s_retry_num = 0;
            xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
            break;
        case SYSTEM_EVENT_STA_DISCONNECTED:
        {
            if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY)
            {
                esp_wifi_connect();
                xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
                s_retry_num++;
                ESP_LOGI(TAG, "retry to connect to the AP");
            }
            ESP_LOGI(TAG, "connect to the AP failn");
            break;
        }
        default:
            break;
    }
    return ESP_OK;
}

void wifi_init_sta()
{
    s_wifi_event_group = xEventGroupCreate();

    tcpip_adapter_init();
    ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL));
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    wifi_config_t wifi_config = {
        .sta = {.ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS},
    };

    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));

#if ENABLE_STATIC_IP
    tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
    tcpip_adapter_dns_info_t dns_info = {0};
    tcpip_adapter_ip_info_t ip_info = {0};
	//可以用手机开的热点来测试
    IP4_ADDR(&ip_info.ip, 172, 20, 10, 3);
    IP4_ADDR(&ip_info.gw, 172, 20, 10, 1);
    IP4_ADDR(&ip_info.netmask, 255, 255, 255, 240);
    IP_ADDR4(&dns_info.ip, 172, 20, 10, 1);
    ESP_ERROR_CHECK(tcpip_adapter_set_dns_info(TCPIP_ADAPTER_IF_STA, TCPIP_ADAPTER_DNS_FALLBACK, &dns_info));
    ESP_ERROR_CHECK(tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
#else

#endif
    ESP_ERROR_CHECK(esp_wifi_start());

    ESP_LOGI(TAG, "wifi_init_sta finished.");
    ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}

void dns_found_cb(const char *name, const ip_addr_t *ipaddr, void *callback_arg)
{
    getIP = *ipaddr;
    ESP_LOGE(TAG, "baidu.com ip is = %d", getIP.u_addr.ip4.addr);
    ESP_LOGI(TAG, "internet connection : %s and ip : %d", error ? "false" : "true", getIP.u_addr.ip4.addr);
}

void app_main()
{

    // Initialize NVS
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);

    ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
    wifi_init_sta();
    EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
    if (bits & WIFI_CONNECTED_BIT)
    {
        printf("Ready to Anasis ~rn");
        struct addrinfo *result;
        int err;
        err = getaddrinfo("www.baidu.com", "80", &hints, &result);
        if (err != 0) 
            printf("getaddrinfo err: %d n", err);
        // 3、将获取到的信息打印出来
        char buf[100]; 
        struct sockaddr_in *ipv4 = NULL; 
        if (result->ai_family == AF_INET)
        {
            ipv4 = (struct sockaddr_in *)result->ai_addr;
            inet_ntop(result->ai_family, &ipv4->sin_addr, buf, sizeof(buf));
            printf("[IPv4-%d]%s [port]%d n", ipv4_cnt, buf, ntohs(ipv4->sin_port));
        }
        else
            printf("got IPv4 err !!!n");
        // 4、释放addrinfo 内存
        freeaddrinfo(result);
    }
}

总结

代码改编至示例,上面的 API 也是自己瞎封装,但也能实现功能,可能有其他更好的方法,有空一起探讨

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/751594.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号