ESP32接入网络后,循环扫描服务器IP及端口状态信息(ESP-IDF)
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案例。
3、程序效果图
ESP32接入WiFi网络后获取到的IP地址信息
ESP32扫描到在线的IP地址,但未扫描到对应的端口,如果服务器未开启,则ESP32会一直循环扫描服务器的IP及端口。
ESP32扫描到服务器的IP地址和端口
服务器的IP地址
ESP32接入服务器后,服务器端收到来自客户端发送的数据
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