ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

07-13 1159阅读

0、代码说明

        本文使用的是ESP32系列的ESP32S3设备开发,ESP-IDF框架版本为ESP-IDF V5.1,在VScode下以ESP-IDF插件的形式对设备开发。后期经过对程序的测试发现,在ESP-IDF v4.4框架下编译开发,也可以实现循环扫描功能,实现功能的程序源码Demo见文末。

1、实现背景

        在嵌入式物联网这一类的项目开发中,硬件设备常作为客户端,通过固定的或非固定的服务器IP地址和端口号向服务器进行通信,上传本地数据到服务器中或接收来自服务器的请求数据。本文主要解决当服务器IP地址并未固定或者因某种原因导致服务器的IP地址发生变动,而硬件设备产品可能已经上市交付等其它因素,并不能及时的通过OTA升级更新客户端的MCU硬件程序,但硬件产品依然需要连接服务器的端口,进行数据交互。

        为了预防避免这些意外,在硬件设备程序的编写中,并不能和往常一样直接固定了服务器IP地址。本博客文章中提供了一种简单可行的方法,即:客户端固定了目标服务器的IP端口,但服务器的IP地址并不固定。当然,也可以先进行对某一固定了IP和端口的服务器进行连接,在多次或者一定时间都不能正常接入服务器后,开启循环扫描同一网段的服务器IP,连接该固定端口或备用端口。

2、开发资料参考

乐鑫官方的ESP-IDF编程API参考指南链接:API 指南 - ESP32-S3 - — ESP-IDF 编程指南 latest 文档 (espressif.com)

通过API编程参考,可以查看ESP32所需要的常用API及其使用的Demo案例。

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

3、程序效果图

ESP32接入WiFi网络后获取到的IP地址信息

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

ESP32扫描到在线的IP地址,但未扫描到对应的端口,如果服务器未开启,则ESP32会一直循环扫描服务器的IP及端口。

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

ESP32扫描到服务器的IP地址和端口

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

服务器的IP地址

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

ESP32接入服务器后,服务器端收到来自客户端发送的数据

ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)

4、程序源码

 ①、main.c

#include 
#include 
#include "esp_wifi.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "network.h"
//设备启动接入WiFi后,循环扫描服务器ip是否在线,通信端口是否打开
int app_main()
{
    printf("Program starting...\n");
    int ret = 0;
    char server_ip[128] = {0};
    uint8_t wifi_ssid[] = "imi-12-1719";
    uint8_t wifi_passwd[] = "imi?61415926";
    
    device_connect_wifi_ap(wifi_ssid, wifi_passwd);
    vTaskDelay(500);
    while(1)
    {
        ret = device_scan_dest_server(server_ip);
        if(ret == 0)
        {
            printf("Server ip:%s\n", server_ip);
            break;
        }
        vTaskDelay(30000 / portTICK_PERIOD_MS);
    }
    
    //连接服务器
    extern int tcp_sock;
    tcp_client_init(server_ip);
    char str[] = "hello server!";
    send(tcp_sock, str, strlen(str)+1, 0);
    close(tcp_sock);
    return 0;
}

②、network.c

#include "network.h"
//ESP-IDF v5.1
static const char *TAG = "wifi_station";
int tcp_sock = -1;
int udp_sock = -1;
esp_ping_handle_t ping;
int ping_flag = -1;
enum {
    PING_IP_OK = 0,
    PING_IP_ERR
};
struct sockaddr_in dest_addr;
/**
  * @brief  连接WiFi事件处理器---处理WiFi和IP事件
  * @param  arg:用户定义的参数
  * @param  event_base:事件基类型
  * @param  event_id:事件具体ID
  * @param  event_data:指向事件数据的指针
  * @retval void
  */
void connect_wifi_ap_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        esp_wifi_connect();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        char addr_str[IP4ADDR_STRLEN_MAX];
        ESP_LOGI(TAG, "got ip:%s", esp_ip4addr_ntoa(&event->ip_info.ip, addr_str, IP4ADDR_STRLEN_MAX));
    }
}
/**
  * @brief  设备连接WiFi AP热点
  * @param  wifi_ssid:WiFi 热点ID
  * @param  wifi_passwd:WiFi密码
  * @retval void
  */
void device_connect_wifi_ap(uint8_t *wifi_ssid, uint8_t *wifi_passwd)
{
    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_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());
    esp_netif_create_default_wifi_sta();
    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &connect_wifi_ap_event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_wifi_ap_event_handler, NULL));
    wifi_config_t wifi_config;
    memcpy(wifi_config.sta.ssid, wifi_ssid, strlen((char *)wifi_ssid)+1);
    memcpy(wifi_config.sta.password, wifi_passwd, strlen((char *)wifi_passwd)+1);
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start());
}
/**
  * @brief  udp客户端初始化
  * @param  None
  * @retval 成功返回0,失败返回-1
  */
int udp_client_init(void)
{
    char host_ip[] = HOST_IP_ADDR;
    int addr_family = 0;
    int ip_protocol = 0;  
#if defined(CONFIG_EXAMPLE_IPV4)
    //struct sockaddr_in dest_addr;
    dest_addr.sin_addr.s_addr = inet_addr(host_ip);
    dest_addr.sin_family = AF_INET;
    dest_addr.sin_port = htons(PORT);
    addr_family = AF_INET;
    ip_protocol = IPPROTO_IP;
#elif defined(CONFIG_EXAMPLE_IPV6)
    struct sockaddr_in6 dest_addr = {0};
    inet6_aton(HOST_IP_ADDR, &dest_addr.sin6_addr);
    dest_addr.sin6_family = AF_INET6;
    dest_addr.sin6_port = htons(PORT);
    dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(EXAMPLE_INTERFACE);
    addr_family = AF_INET6;
    ip_protocol = IPPROTO_IPV6;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
    struct sockaddr_storage dest_addr = {0};
    ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_DGRAM, &ip_protocol, &addr_family, &dest_addr));
#endif
    extern int udp_sock;
    udp_sock = socket(addr_family, SOCK_DGRAM, ip_protocol);
    if (udp_sock 
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]