ESP32(3)UDP通信
对于 lwIP 的 Socket 的使用方式,它与文件操作非常相似。在文件操作中,我们首先打开文件,然后进行读/写操作,最后关闭文件。在TCP/IP网络通信中,也存在着相同的操作流程,但所使用的接口不再是文件描述符或 FILE*,而是被称为 Socket 的描述符。通过 Socket,我们可以进行读、写、打开和关闭操作来进行网络数据的传输。此外,还有一些辅助函数,如查询域名/IP 地址和设置 Socket 功能等。在本章中,我们将使用 Socket 编程接口来实现 UDP 实验。
Socket 编程 UDP 连接流程
在实现 UDP协议之前,用户需要按照以下步骤配置结构体 sockaddr_in的成员变量,以便建立 UDP 连接:
①:配置 ESP32-S3 设备连接网络(必须的,因为 WiFi 是无线通信,所以需搭建通信桥梁)。
②:将 sin_family 设置为 AF_INET,表示使用 IPv4 网络协议。
③:设置 sin_port 为所需的端口号,例如 8080。
④:设置 sin_addr.s_addr 为本地 IP 地址。
⑤:调用函数 Socket 创建 Socket 连接。请注意,该函数的第二个参数指定连接类型。SOCK_STREAM 表示 TCP 连接,而 SOCK_DGRAM 表示 UDP 连接。
⑥:调用函数 bind 将本地服务器地址与 Socket 进行绑定。
⑦:调用适当的收发函数来接收或发送数据。
通过遵循这些步骤,用户可以成功地配置并建立 UDP 连接,以实现数据的发送和接收。
UDP-Server
/** SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD** SPDX-License-Identifier: CC0-1.0*/#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_chip_info.h"
#include "esp_eap_client.h"
#include "esp_smartconfig.h"
#include "esp_flash.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "esp_mac.h"#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>static const char *TAG = "network";//=============================================================smart config===============================================================
static EventGroupHandle_t s_wifi_event_group;static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;static void smartconfig_task(void * parm);static void 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) {xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {esp_wifi_connect();xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {ESP_LOGI(TAG, "Scan done");} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {ESP_LOGI(TAG, "Found channel");} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {ESP_LOGI(TAG, "Got SSID and password");smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;wifi_config_t wifi_config;uint8_t ssid[33] = { 0 };uint8_t password[65] = { 0 };uint8_t rvd_data[33] = { 0 };bzero(&wifi_config, sizeof(wifi_config_t));memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));#ifdef CONFIG_SET_MAC_ADDRESS_OF_TARGET_APwifi_config.sta.bssid_set = evt->bssid_set;if (wifi_config.sta.bssid_set == true) {ESP_LOGI(TAG, "Set MAC address of target AP: "MACSTR" ", MAC2STR(evt->bssid));memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));}
#endifmemcpy(ssid, evt->ssid, sizeof(evt->ssid));memcpy(password, evt->password, sizeof(evt->password));ESP_LOGI(TAG, "SSID:%s", ssid);ESP_LOGI(TAG, "PASSWORD:%s", password);if (evt->type == SC_TYPE_ESPTOUCH_V2) {ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );ESP_LOGI(TAG, "RVD_DATA:");for (int i=0; i<33; i++) {printf("%02x ", rvd_data[i]);}printf("\n");}ESP_ERROR_CHECK( esp_wifi_disconnect() );ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );esp_wifi_connect();} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);}
}static void initialise_wifi(void)
{ESP_ERROR_CHECK(esp_netif_init());s_wifi_event_group = xEventGroupCreate();ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();assert(sta_netif);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, &event_handler, NULL) );ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );ESP_ERROR_CHECK( esp_wifi_start() );
}static void smartconfig_task(void * parm)
{EventBits_t uxBits;ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );while (1) {uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);if(uxBits & CONNECTED_BIT) {ESP_LOGI(TAG, "WiFi Connected to ap");}if(uxBits & ESPTOUCH_DONE_BIT) {ESP_LOGI(TAG, "smartconfig over");esp_smartconfig_stop();vTaskDelete(NULL);}}
}
//======================================================udp server=================================================================
#define PORT 8080
#define CONFIG_EXAMPLE_IPV4static void udp_server_task(void *pvParameters)
{char rx_buffer[128];char addr_str[128];int addr_family = (int)pvParameters;int ip_protocol = 0;struct sockaddr_in6 dest_addr;while (1) {if (addr_family == AF_INET) {struct sockaddr_in *dest_addr_ip4 = (struct sockaddr_in *)&dest_addr;dest_addr_ip4->sin_addr.s_addr = htonl(INADDR_ANY);dest_addr_ip4->sin_family = AF_INET;dest_addr_ip4->sin_port = htons(PORT);ip_protocol = IPPROTO_IP;} else if (addr_family == AF_INET6) {bzero(&dest_addr.sin6_addr.un, sizeof(dest_addr.sin6_addr.un));dest_addr.sin6_family = AF_INET6;dest_addr.sin6_port = htons(PORT);ip_protocol = IPPROTO_IPV6;}int sock = socket(addr_family, SOCK_DGRAM, ip_protocol);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);break;}ESP_LOGI(TAG, "Socket created");#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)int enable = 1;lwip_setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &enable, sizeof(enable));
#endif#if defined(CONFIG_EXAMPLE_IPV4) && defined(CONFIG_EXAMPLE_IPV6)if (addr_family == AF_INET6) {// Note that by default IPV6 binds to both protocols, it is must be disabled// if both protocols used at the same time (used in CI)int opt = 1;setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &opt, sizeof(opt));}
#endif// Set timeoutstruct timeval timeout;timeout.tv_sec = 10;timeout.tv_usec = 0;setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);int err = bind(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err < 0) {ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);}ESP_LOGI(TAG, "Socket bound, port %d", PORT);struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6socklen_t socklen = sizeof(source_addr);#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)struct iovec iov;struct msghdr msg;struct cmsghdr *cmsgtmp;u8_t cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];iov.iov_base = rx_buffer;iov.iov_len = sizeof(rx_buffer);msg.msg_control = cmsg_buf;msg.msg_controllen = sizeof(cmsg_buf);msg.msg_flags = 0;msg.msg_iov = &iov;msg.msg_iovlen = 1;msg.msg_name = (struct sockaddr *)&source_addr;msg.msg_namelen = socklen;
#endifwhile (1) {ESP_LOGI(TAG, "Waiting for data");
#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)int len = recvmsg(sock, &msg, 0);
#elseint len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);
#endif// Error occurred during receivingif (len < 0) {ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);break;}// Data receivedelse {// Get the sender's ip address as stringif (source_addr.ss_family == PF_INET) {inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
#if defined(CONFIG_LWIP_NETBUF_RECVINFO) && !defined(CONFIG_EXAMPLE_IPV6)for ( cmsgtmp = CMSG_FIRSTHDR(&msg); cmsgtmp != NULL; cmsgtmp = CMSG_NXTHDR(&msg, cmsgtmp) ) {if ( cmsgtmp->cmsg_level == IPPROTO_IP && cmsgtmp->cmsg_type == IP_PKTINFO ) {struct in_pktinfo *pktinfo;pktinfo = (struct in_pktinfo*)CMSG_DATA(cmsgtmp);ESP_LOGI(TAG, "dest ip: %s", inet_ntoa(pktinfo->ipi_addr));}}
#endif} else if (source_addr.ss_family == PF_INET6) {inet6_ntoa_r(((struct sockaddr_in6 *)&source_addr)->sin6_addr, addr_str, sizeof(addr_str) - 1);}rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string...ESP_LOGI(TAG, "Received %d bytes from %s:", len, addr_str);ESP_LOGI(TAG, "%s", rx_buffer);int err = sendto(sock, rx_buffer, len, 0, (struct sockaddr *)&source_addr, sizeof(source_addr));if (err < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);break;}}}if (sock != -1) {ESP_LOGE(TAG, "Shutting down socket and restarting...");shutdown(sock, 0);close(sock);}}vTaskDelete(NULL);
}//===================================================================================================================================void app_main(void)
{printf("Hello world!\n");/* Print chip information */esp_chip_info_t chip_info;uint32_t flash_size;esp_chip_info(&chip_info);printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",CONFIG_IDF_TARGET,chip_info.cores,(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");unsigned major_rev = chip_info.revision / 100;unsigned minor_rev = chip_info.revision % 100;printf("silicon revision v%d.%d, ", major_rev, minor_rev);if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {printf("Get flash size failed");return;}printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());// Initialize NVSesp_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);//initinitialise_wifi();#ifdef CONFIG_EXAMPLE_IPV4xTaskCreate(udp_server_task, "udp_server", 4096, (void*)AF_INET, 5, NULL);#endif#ifdef CONFIG_EXAMPLE_IPV6xTaskCreate(udp_server_task, "udp_server", 4096, (void*)AF_INET6, 5, NULL);#endifwhile(1) {vTaskDelay(1000);}
}
测试:
使用网络调试工具创建一个UDP Client,发送数据:
UDP-Client
/** SPDX-FileCopyrightText: 2010-2022 Espressif Systems (Shanghai) CO LTD** SPDX-License-Identifier: CC0-1.0*/#include <stdio.h>
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_chip_info.h"
#include "esp_eap_client.h"
#include "esp_smartconfig.h"
#include "esp_flash.h"
#include "nvs_flash.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_wifi.h"
#include "esp_netif.h"
#include "esp_mac.h"#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>static const char *TAG = "network";//=============================================================smart config===============================================================
static EventGroupHandle_t s_wifi_event_group;static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;static void smartconfig_task(void * parm);static void 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) {xTaskCreate(smartconfig_task, "smartconfig_task", 4096, NULL, 3, NULL);} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {esp_wifi_connect();xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {ESP_LOGI(TAG, "Scan done");} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {ESP_LOGI(TAG, "Found channel");} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {ESP_LOGI(TAG, "Got SSID and password");smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;wifi_config_t wifi_config;uint8_t ssid[33] = { 0 };uint8_t password[65] = { 0 };uint8_t rvd_data[33] = { 0 };bzero(&wifi_config, sizeof(wifi_config_t));memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));#ifdef CONFIG_SET_MAC_ADDRESS_OF_TARGET_APwifi_config.sta.bssid_set = evt->bssid_set;if (wifi_config.sta.bssid_set == true) {ESP_LOGI(TAG, "Set MAC address of target AP: "MACSTR" ", MAC2STR(evt->bssid));memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));}
#endifmemcpy(ssid, evt->ssid, sizeof(evt->ssid));memcpy(password, evt->password, sizeof(evt->password));ESP_LOGI(TAG, "SSID:%s", ssid);ESP_LOGI(TAG, "PASSWORD:%s", password);if (evt->type == SC_TYPE_ESPTOUCH_V2) {ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );ESP_LOGI(TAG, "RVD_DATA:");for (int i=0; i<33; i++) {printf("%02x ", rvd_data[i]);}printf("\n");}ESP_ERROR_CHECK( esp_wifi_disconnect() );ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );esp_wifi_connect();} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);}
}static void initialise_wifi(void)
{ESP_ERROR_CHECK(esp_netif_init());s_wifi_event_group = xEventGroupCreate();ESP_ERROR_CHECK(esp_event_loop_create_default());esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();assert(sta_netif);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, &event_handler, NULL) );ESP_ERROR_CHECK( esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL) );ESP_ERROR_CHECK( esp_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );ESP_ERROR_CHECK( esp_wifi_start() );
}static void smartconfig_task(void * parm)
{EventBits_t uxBits;ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );while (1) {uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);if(uxBits & CONNECTED_BIT) {ESP_LOGI(TAG, "WiFi Connected to ap");}if(uxBits & ESPTOUCH_DONE_BIT) {ESP_LOGI(TAG, "smartconfig over");esp_smartconfig_stop();vTaskDelete(NULL);}}
}
//======================================================udp client=================================================================
//#define CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN
#define CONFIG_EXAMPLE_IPV4#ifdef CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN
#include "addr_from_stdin.h"
#endif#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR "192.168.4.178"
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif#define PORT 8080static const char *payload = "Message from ESP32 ";static void udp_client_task(void *pvParameters)
{char rx_buffer[128];char host_ip[] = HOST_IP_ADDR;int addr_family = 0;int ip_protocol = 0;while (1) {#if defined(CONFIG_EXAMPLE_IPV4)struct sockaddr_in dest_addr;dest_addr.sin_addr.s_addr = inet_addr(HOST_IP_ADDR);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));
#endifint sock = socket(addr_family, SOCK_DGRAM, ip_protocol);if (sock < 0) {ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);break;}// Set timeoutstruct timeval timeout;timeout.tv_sec = 10;timeout.tv_usec = 0;setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);ESP_LOGI(TAG, "Socket created, sending to %s:%d", HOST_IP_ADDR, PORT);while (1) {int err = sendto(sock, payload, strlen(payload), 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));if (err < 0) {ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);break;}ESP_LOGI(TAG, "Message sent");struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6socklen_t socklen = sizeof(source_addr);int len = recvfrom(sock, rx_buffer, sizeof(rx_buffer) - 1, 0, (struct sockaddr *)&source_addr, &socklen);// Error occurred during receivingif (len < 0) {ESP_LOGE(TAG, "recvfrom failed: errno %d", errno);break;}// Data receivedelse {rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a stringESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);ESP_LOGI(TAG, "%s", rx_buffer);if (strncmp(rx_buffer, "OK: ", 4) == 0) {ESP_LOGI(TAG, "Received expected message, reconnecting");break;}}vTaskDelay(2000 / portTICK_PERIOD_MS);}if (sock != -1) {ESP_LOGE(TAG, "Shutting down socket and restarting...");shutdown(sock, 0);close(sock);}}vTaskDelete(NULL);
}//===================================================================================================================================void app_main(void)
{printf("Hello world!\n");/* Print chip information */esp_chip_info_t chip_info;uint32_t flash_size;esp_chip_info(&chip_info);printf("This is %s chip with %d CPU core(s), %s%s%s%s, ",CONFIG_IDF_TARGET,chip_info.cores,(chip_info.features & CHIP_FEATURE_WIFI_BGN) ? "WiFi/" : "",(chip_info.features & CHIP_FEATURE_BT) ? "BT" : "",(chip_info.features & CHIP_FEATURE_BLE) ? "BLE" : "",(chip_info.features & CHIP_FEATURE_IEEE802154) ? ", 802.15.4 (Zigbee/Thread)" : "");unsigned major_rev = chip_info.revision / 100;unsigned minor_rev = chip_info.revision % 100;printf("silicon revision v%d.%d, ", major_rev, minor_rev);if(esp_flash_get_size(NULL, &flash_size) != ESP_OK) {printf("Get flash size failed");return;}printf("%" PRIu32 "MB %s flash\n", flash_size / (uint32_t)(1024 * 1024),(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");printf("Minimum free heap size: %" PRIu32 " bytes\n", esp_get_minimum_free_heap_size());// Initialize NVSesp_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);//initinitialise_wifi();xTaskCreate(udp_client_task, "udp_client", 4096, NULL, 5, NULL);while(1) {vTaskDelay(1000);}
}
测试:使用网络调试工具创建UDP-Server,配网后等待接收数据。
相关文章:
ESP32(3)UDP通信
对于 lwIP 的 Socket 的使用方式,它与文件操作非常相似。在文件操作中,我们首先打开文件,然后进行读/写操作,最后关闭文件。在TCP/IP网络通信中,也存在着相同的操作流程,但所使用的接口不再是文件描述符或 …...
汽车机械钥匙升级一键启动的优点
汽车机械钥匙升级一键启动的优点主要包括: 便捷性:一键启动功能的引入极大地提升了用车便捷性。车主无需翻找钥匙,只需在车辆感应范围内轻触启动键,即可轻松发动汽车。 安全性:移动管家专车专用一键启动系统配备了防…...
【matlab例程】三维下的TDOA定位和EKF轨迹滤波例程,TDOA的锚点数量可自定义(订阅专栏后可获得完整代码)
本文所述的MATLAB例程实现了TDOA定位和扩展卡尔曼滤波(EKF)来提高位置估计的准确性,并通过可视化结果进行分析。 文章目录 运行结果MATLAB代码程序讲解关键步骤和功能步骤解释注意事项总结运行结果 三维轨迹: 三维误差曲线: RMSE曲线: 命令行输出内容:...
个人blog系统 前后端分离 前端js后端go
系统设计: 1.使用语言:前端使用vue,并使用axios向后端发送数据。后端使用的是go的gin框架,并使用grom连接数据库实现数据存储读取。 2.设计结构: 最终展示:仅展示添加模块,其他模块基本相似 前…...
OSG简介
OSG OpenSceneGraph (简称 OSG) 是一个开源的高性能3D图形库。 作用 它为开发者提供了一个强大的API,处理和渲染复杂的3D图形。 特点 OSG基于OpenGL构建,提供了对现代图形技术的支持,如着色器、纹理映射、光照模型等高级特性。 跨平台支…...
社区版Uos20.9从源码编译QT5.15.2
主要是在这个文章上学的究极保姆式教你如何在Ubuntu上源码安装Qt5.15.2_ubuntu安装qt5.15.2-CSDN博客 但原文上在环境变量的配置上真用在 uso上好像不行,要加一些引号和$号。原文的测试编译代码也有些问题,include上少了类。略作修改,在UOS社…...
AI学习第二天--大模型压缩(量化、剪枝、蒸馏、低秩分解)
目录 1. 量化:压缩大象的“脂肪” 比喻 技术逻辑 2. 剪枝:修剪大象的“无效毛发” 比喻 技术逻辑 3. 知识蒸馏:让大象“师从巨象” 比喻 技术逻辑 4. 低秩分解:把大象“折叠成纸偶” 比喻 技术逻辑 5. 推理优化&#…...
C++ —— 线程同步(互斥锁)
C —— 线程同步(互斥锁) 线程同步互斥锁(互斥量)测试代码mutex互斥锁 线程同步 线程同步:多线程协同工作,协商如何使用共享资源。 C11线程同步包含三部分内容: 互斥锁(互斥量&…...
相对路径跳转和绝对路径跳转有什么区别?
在 Vue 3 中使用路由跳转时,相对路径跳转和绝对路径跳转在使用方式、适用场景等方面存在明显区别,以下为你详细介绍: 定义 绝对路径跳转:指的是使用完整的路径来进行路由导航,路径以 / 开头,无论当前处于…...
Flume详解——介绍、部署与使用
1. Flume 简介 Apache Flume 是一个专门用于高效地 收集、聚合、传输 大量日志数据的 分布式、可靠 的系统。它特别擅长将数据从各种数据源(如日志文件、消息队列等)传输到 HDFS、HBase、Kafka 等大数据存储系统。 特点: 可扩展࿱…...
笔记类AI应用体验
笔记类AI应用体验 叮当好记视频一键转笔记, 祝你学习效率起飞 IMAGet笔记印象笔记(Evernote):Notion:Trilium Notes:二、开始搭建三、搭建步骤四、创建博客 Obsidian:案例让ai帮我执行大模型学习…...
Mysql篇——SQL优化
本篇将带领各位了解一些常见的sql优化方法,学到就是赚到,一起跟着练习吧~ SQL优化 准备工作 准备的话我们肯定是需要一张表的,什么表都可以,这里先给出我的表结构(表名:userinfo) 通过sql查看…...
【css酷炫效果】纯CSS实现故障文字特效
【css酷炫效果】纯CSS实现故障文字特效 缘创作背景html结构css样式完整代码基础版进阶版(3D效果) 效果图 想直接拿走的老板,链接放在这里:https://download.csdn.net/download/u011561335/90492053 缘 创作随缘,不定时更新。 创作背景 刚…...
【Java】链表(LinkedList)(图文版)
本博客总结了Java当中链表的实现,以及相关方法的使用,在最后附带了一些常见链表相关处理技巧,希望对你有帮助! ps:可拷贝到IDEA上自行测试,代码全部完成测试。 一.链表概述 1.什么是链表? 链…...
审批工作流系统xFlow
WorkFlow-审批流程系统 该项目为完全开源免费项目 可用于学习或搭建初始化审批流程系统 希望有用的小伙伴记得点个免费的star gitee仓库地址 仿钉钉飞书工作审批流系统 介绍 前端技术栈: vue3 ts vite arcodesign eslint 后端技术栈:springbootspring mvc mybatis mavenmysq…...
UNION,UNION ALL 的详细用法
目录 一、基本概念 二、核心区别 三、语法使用规则 四、代码实演示 4.1 两张表字段相同,字段顺序也相同 4.2 两张表字段相同。但字段顺序不同 4.3 两张表存在相同字段,但一张表字段多,一张表字段少 一、基本概念 操作符功能描述去重处…...
Java 集合遍历过程中修改数据触发 Fail-Fast 机制 ,导致报ConcurrentModificationException异常
Java Fail-Fast 机制 Fail-Fast 机制是 Java 集合框架中的一种错误检测机制,用于在遍历集合时检测结构修改。如果在迭代器创建之后,集合被修改(例如添加或删除元素),并且这种修改不是通过迭代器自身的 remove() 方法进…...
Javascript 日期相关计算
1、获取当前日期的前一天 // 获取当前日期let today new Date();today.setDate(today.getDate() - 1);// 转换为本地日期字符串格式let yesterdayStr today.toISOString().slice(0, 10);console.log(yesterdayStr); // 例如: "2023-04-03" (格式取决于地区设置) 2…...
自动驾驶背后的数学:特征提取中的线性变换与非线性激活
在上一篇博客「自动驾驶背后的数学:从传感器数据到控制指令的函数嵌套」—— 揭秘人工智能中的线性函数、ReLU 与复合函数中,我们初步探讨了自动驾驶技术中从传感器数据到控制指令的函数嵌套流程,其中提到了特征提取模块对传感器数据进行线性…...
DNS解析查询工具
dig命令 1 常用命令 命令:dig 您的域名(示例:dig www.baidu.com) 2、根据解析记录查询,比如MX,CNAME,NS,PTR等,只需将类型加在命令后面即可。 示例:dig bai…...
【eNSP实战】(续)一个AC多个VAP的实现—将隧道转发改成直接转发
在 一个AC多个VAP的实现—CAPWAP隧道转发 此篇文章配置的基础上,将隧道转发改成直接转发 一、改成直接转发需要改动的配置 (一)将连接AP的接口改成trunk口,并允许vlan100、101、102通过 [AC1]interface GigabitEthernet 0/0/8 …...
解决远程卡在下载vscode-server的问题,一键安装脚本
vscode-server 下载与安装脚本 vscode-server一键安装脚本 简介 此脚本用于下载并安装指定提交 ID 和架构的 VS Code Server。用户可以选择不同的架构,并输入对应的 VS Code 提交 ID 来下载和安装 vscode-server。VS Code提交ID可以在VS Code界面“帮助>关于…...
【unity实战】用unity封装一个复杂全面且带不同射击模式的飞机大战射击系统
考虑到每个人基础可能不一样,且并不是所有人都有同时做2D、3D开发的需求,所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】:主要讲解C#的基础语法,包括变量、数据类型、运算符、流程控制、面向对象等,适合没有编程基础的…...
LeetCode[42] 接雨水
动态规划 left_max[i] height[i]左侧的最高高度right_max[i] height[i]右侧的最高高度height[i]能接多少水?min(left_max[i], right_max[i])-height[i] class Solution { public:int trap(vector<int>& height) {int len height.size();vector<in…...
c++ 基础题目lambda
1. auto lambda = [](double x) { return static_cast<int>(x); }; 是 匿名函数对象 ,不可直接声明 a.可以赋值给一个与其类型兼容的 std::function 类型的对象 std::function<int(int, int)> lambda = [](int x, int y) { return x + y; }; b.使用具体的 lambda …...
RTSP/Onvif安防视频EasyNVR平台 vs.多协议接入视频汇聚EasyCVR平台:设备分组的区别
EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力,能对接入的视频流进行处理与多端分发,包括RTSP、RTMP、HTTP-FLV、W…...
网络编程套接字【端口号/TCPUDP/网络字节序/socket编程接口/UDPTCP网络实验】
网络编程套接字 0. 前言1. 认识端口号2. 认识TCP和UDP协议3. 网络字节序4. socket编程接口5. 实现一个简单的UDP网络程序5.1 需求分析5.2 头文件准备5.3 服务器端设计5.4 客户端设计5.5 本地测试5.6 跨网络测试5.7 UDP小应用——客户端输入命令,服务器端执行 6. 地址…...
【C语言预编译处理精选题】
C语言预编译处理精选题 一、选择易错题1.1 纯文本替换,注意优先级!1.2 再来一道文本替换,别马虎1.3 宏定义的替换1.4带参数宏定义的空格问题1.5 " "的include1.6 条件编译1.7 预编译概念 二、填空易错题2.1 注意两个连续的 i2.2 异…...
云钥科技工业相机定制服务,助力企业实现智能智造
在工业自动化、智能制造和机器视觉快速发展的今天,工业相机作为核心感知设备,其性能直接决定了检测精度、生产效率和产品质量。然而,标准化工业相机往往难以满足复杂多样的应用场景需求,工业相机定制逐渐成为企业突破技术瓶颈…...
用了Cline和华为云的大模型,再也回不去了
这两年AI火热,受影响最大的还是程序员群体,因为编程语言是高度形式化的,完全可以用BNF等形式精确地定义,不像自然语言那样,容易出现歧义。另外开源是软件界的潮流,GitHub上有海量的开源代码可供AI来训练&am…...
vs2017版本与arcgis10.1的ArcObject SDK for .NET兼容配置终结解决方案
因电脑用的arcgis10.1,之前安装的vs2010正常能使用AO和AE,安装vs2017后无法使用了,在重新按照新版本arcgis engine或者arcObject费时费力,还需要重新查找资源。 用vs2017与arc10.1的集成主要两个问题,1:安装后vs中没有…...
Java对接微信支付全过程详解
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
微软 System Center Configuration Manager(SCCM)的组件文件
微软 System Center Configuration Manager(SCCM) 或 Microsoft Endpoint Configuration Manager(MECM) 的组件文件,属于企业级设备管理工具的一部分。以下是具体说明: C:\Windows\CCM\smsswd.exe C:\Windows\CCM\tsmanager.exe smsswd.exe 和 tsmanager.exe 是 Micros…...
C语言和C++到底有什么关系?
C 读作“C 加加”,是“C Plus Plus”的简称。 顾名思义,C 就是在 C 语言的基础上增加了新特性,玩出了新花样,所以才说“Plus”,就像 Win11 和 Win10、iPhone 15 和 iPhone 15 Pro 的关系。 C 语言是 1972 年由美国贝…...
10.PE导出表
一:定位导出表 PIMAGE_NT_HEADERS->OptionalHeader->DataDirectory[0] typedef struct _IMAGE_DATA_DIRECTORY {DWORD VirtualAddress; // 导出表的RVADWORD Size; // 导出表大小(没用) } IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY; 该结构的Vi…...
springBoot中不添加依赖 , 手动生成一个token ,并校验token,在统一拦截器中进行校验 (使用简单 , 但是安全性会低一点)
要在 Spring Boot 里实现接口统一拦截并校验 Token,可以借助 Spring 的拦截器机制。下面是具体的实现步骤和代码示例。 1. 创建 Token 工具类 import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgori…...
VSCode C/C++ 环境搭建指南
一、前言 Visual Studio Code(简称 VSCode)是一款轻量级且功能强大的跨平台代码编辑器,凭借丰富的插件生态和高度的可定制性,深受开发者喜爱。对于 C/C 开发者而言,在 VSCode 中搭建开发环境,能够获得灵活…...
ES6(4) Map 集合详解
1. Map 集合简介 Map 是 ES6 提供的一种新的键值对数据结构,与普通对象(Object)不同,Map 的键可以是任意类型(包括对象、函数等)。 2. 创建 Map 集合 可以使用 new Map() 创建一个 Map,并在括…...
DeepSeek私有化部署与安装浏览器插件内网穿透远程访问实战
文章目录 前言1. 本地部署OllamaDeepSeek2. Page Assist浏览器插件安装与配置3. 简单使用演示4. 远程调用大模型5. 安装内网穿透6. 配置固定公网地址 前言 最近,国产AI大模型Deepseek成了网红爆款,大家纷纷想体验它的魅力。但随着热度的攀升,…...
【设计模式】建造者模式
三、建造者模式 3.3 建造者模式 建造者(Builder) 模式也称构建器模式、构建者模式或生成器模式,同工厂模式或原型 模式一样,也是一种创建型模式。建造者模式比较复杂,不太常用,但这并不表示不需要了 解和掌握该模式。建造者模式…...
一场由 ES 分片 routing 引发的问题
一场由 ES 分片 routing 引发的问题 ES 结构 {"poroperties": {"joinType": {"type": "join","eager_global_ordinals": true,"relations": {"spu": "sku"}},"id":{"type&q…...
搭建Python量化开发环境:从零开始的完整指南
搭建Python量化开发环境:从零开始的完整指南 在量化投资领域,一个稳定且高效的开发环境是成功的关键。本文将引导你一步步搭建起自己的Python量化开发环境,确保你能够顺利开始编写和运行量化策略。 🚀量化软件开通 Ὠ…...
JavaScript日期区间计算:精准解析年月日差异
一、应用场景与功能概述 在日常的制作项目或者是练习,我们经常需要计算两个日期之间的精确时间差。本文将通过一个JavaScript日期计算函数,详细解析如何实现精准的年/月/日差异计算,并探讨实际开发中的常见问题和解决方案。 二、核心功能解…...
大数据学习(71)-三范式构成
🍋🍋大数据学习🍋🍋 🔥系列专栏: 👑哲学语录: 用力所能及,改变世界。 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一…...
el-table 插槽踩过的坑 :slot-scope 和#default的区别
slot-scope和#default是Vue中用于定义插槽的两种不同语法,它们在Vue 2和Vue 3中有不同的应用场景和语法规则。 slot-scope 在Vue 2.x中,slot-scope是用于声明具名插槽并获取父组件传递过来的数据的主要方式。通过slot-scope可以定义一个变量scop…...
Linux一键安装node.js【脚本】
node.js一般不用系统的apt安装,而是用nvm这个前端的应用商店安装 node.js是js环境,nvm是安装nodejs管理器。npm是nodejs里的包管理器,安装模块的,类似于python的pip 把以下代码复制保存在一个文件里 比如nano install_nodejs.sh …...
vue3:pinia安装及其使用
一、安装 Pinia 的步骤 1、安装 Pinia npm install pinia 2、在 Vue 应用中引入 Pinia 在 main.js 中引入并注册 Pinia: import { createApp } from vue; import { createPinia } from pinia; import App from ./App.vue;const app createApp(App); app…...
vue2升级Vue3--native、对inheritAttrs作用做以解释、声明的prop属性和未声明prop的属性
native取消 在 Vue 3 中,v-on 的 .native 修饰符已经被移除。在 Vue 2 中,.native 修饰符用于在组件的根元素上监听原生 DOM 事件,但在 Vue 3 中,这一行为发生了变化。 在 Vue 3 中,所有未在子组件的 emits 选项中定…...
【漫话机器学习系列】146.Softmax 激活函数(Softmax Activation Function)
Softmax 激活函数详解 1. Softmax 函数概述 Softmax 函数(Softmax Activation Function)是一种常用于多分类任务的激活函数,广泛应用于机器学习和深度学习模型,特别是在神经网络的输出层。它的主要作用是将输入的多个实数值转换…...
解决:ModuleNotFoundError: No module named ‘_sqlite3‘
报错: from _sqlite3 import * ModuleNotFoundError: No module named _sqlite3安装sqlite3支持组件: sudo apt-get install libsqlite3-dev进入之前下载的python包下,重新编译和安装Python ./configure --enable-loadable-sqlite-extensions make &a…...