ESP-IDF 5.4.2删除ping会话时出现send error=0错误求解决方案
ESP-IDF 5.4.2 Ping功能偶发
send error=0问题排查思路 问题描述
在ESP-IDF 5.4.2中实现Ping功能,偶尔会出现错误日志:E (185212) ping_sock: send error=0。尝试使用SemaphoreHandle_t同步但效果不佳,当前通过调用PingIp(192.168.1.23, 2, 100, 2000)获取Ping结果。
实现代码
static E_COMMON_Status ping_result; static void on_ping_success(esp_ping_handle_t hdl, void *args) { ping_result = COMMON_STATUS_OK; } static void on_ping_timeout(esp_ping_handle_t hdl, void *args) { } static void on_ping_end(esp_ping_handle_t hdl, void *args) { uint32_t transmitted; uint32_t received; uint32_t total_time_ms; esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted)); esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received)); esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); } E_COMMON_Status PingIp(char *ip_string, uint8_t pingCount, uint8_t pingInterval, uint8_t pingTimeout) { ping_result = COMMON_STATUS_KO; MY_LOGI_MQTT(TAG, "PING:AVVIO DEL PING SU %s", ip_string); ip_addr_t target_addr; if (!inet_aton(ip_string, &target_addr)) { MY_LOGI_MQTT(TAG, "Conversione IP \"%s\" fallita", ip_string); return COMMON_STATUS_KO; } esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG(); config.target_addr = target_addr; config.count = pingCount; config.interval_ms = pingInterval; config.timeout_ms = pingTimeout; esp_ping_callbacks_t cbs = { .on_ping_success = on_ping_success, .on_ping_timeout = on_ping_timeout, .on_ping_end = on_ping_end, .cb_args = NULL}; // ping_result = COMMON_STATUS_KO; esp_ping_handle_t ping; esp_err_t err = esp_ping_new_session(&config, &cbs, &ping); if (err != ESP_OK) { MY_LOGI_MQTT(TAG, "esp_ping_new_session errore: %d", err); return COMMON_STATUS_KO; } err = esp_ping_start(ping); if (err != ESP_OK) { MY_LOGI_MQTT(TAG, "esp_ping_start errore: %d", err); esp_ping_delete_session(ping); return COMMON_STATUS_KO; } vTaskDelay((config.timeout_ms * config.count + 500) / portTICK_PERIOD_MS); esp_ping_stop(ping); esp_ping_delete_session(ping); if (ping_result == COMMON_STATUS_OK) { MY_LOGI_MQTT(TAG, "STATO DEL PING: OK"); } else { MY_LOGI_MQTT(TAG, "STATO DEL PING: KO"); } return ping_result; }
解决思路
- 修正任务延迟计算逻辑:当前
vTaskDelay的时间计算错误,总耗时应该是(pingCount-1)*pingInterval + pingTimeout,而不是pingTimeout*pingCount。错误的延迟会导致Ping会话还在发送数据包时就被强制停止,引发send error=0(发送操作因Socket关闭被中断)。 - 正确使用信号量同步:之前信号量效果差是因为使用方式不正确。应该在
on_ping_end回调中释放信号量,让主线程精准等待Ping会话结束,避免提前终止。示例代码:static SemaphoreHandle_t ping_sem; static void on_ping_end(esp_ping_handle_t hdl, void *args) { uint32_t transmitted; uint32_t received; uint32_t total_time_ms; esp_ping_get_profile(hdl, ESP_PING_PROF_REQUEST, &transmitted, sizeof(transmitted)); esp_ping_get_profile(hdl, ESP_PING_PROF_REPLY, &received, sizeof(received)); esp_ping_get_profile(hdl, ESP_PING_PROF_DURATION, &total_time_ms, sizeof(total_time_ms)); xSemaphoreGive(ping_sem); // 会话结束后释放信号量 } E_COMMON_Status PingIp(char *ip_string, uint8_t pingCount, uint8_t pingInterval, uint8_t pingTimeout) { ping_result = COMMON_STATUS_KO; MY_LOGI_MQTT(TAG, "PING:AVVIO DEL PING SU %s", ip_string); ip_addr_t target_addr; if (!inet_aton(ip_string, &target_addr)) { MY_LOGI_MQTT(TAG, "Conversione IP \"%s\" fallita", ip_string); return COMMON_STATUS_KO; } esp_ping_config_t config = ESP_PING_DEFAULT_CONFIG(); config.target_addr = target_addr; config.count = pingCount; config.interval_ms = pingInterval; config.timeout_ms = pingTimeout; esp_ping_callbacks_t cbs = { .on_ping_success = on_ping_success, .on_ping_timeout = on_ping_timeout, .on_ping_end = on_ping_end, .cb_args = NULL}; // 创建二进制信号量 ping_sem = xSemaphoreCreateBinary(); if (!ping_sem) { MY_LOGI_MQTT(TAG, "Failed to create semaphore"); return COMMON_STATUS_KO; } esp_ping_handle_t ping; esp_err_t err = esp_ping_new_session(&config, &cbs, &ping); if (err != ESP_OK) { MY_LOGI_MQTT(TAG, "esp_ping_new_session errore: %d", err); vSemaphoreDelete(ping_sem); return COMMON_STATUS_KO; } err = esp_ping_start(ping); if (err != ESP_OK) { MY_LOGI_MQTT(TAG, "esp_ping_start errore: %d", err); esp_ping_delete_session(ping); vSemaphoreDelete(ping_sem); return COMMON_STATUS_KO; } // 等待Ping会话结束,超时时间设为总预估耗时+1000ms TickType_t wait_time = ((config.timeout_ms + config.interval_ms*(config.count-1)) + 1000) / portTICK_PERIOD_MS; if (xSemaphoreTake(ping_sem, wait_time) != pdTRUE) { MY_LOGI_MQTT(TAG, "Ping session timeout"); esp_ping_stop(ping); } esp_ping_delete_session(ping); vSemaphoreDelete(ping_sem); if (ping_result == COMMON_STATUS_OK) { MY_LOGI_MQTT(TAG, "STATO DEL PING: OK"); } else { MY_LOGI_MQTT(TAG, "STATO DEL PING: KO"); } return ping_result; } - 添加错误回调捕获细节:在
esp_ping_callbacks_t中添加.on_ping_error回调,获取具体错误码,帮助定位问题:static void on_ping_error(esp_ping_handle_t hdl, void *args, esp_err_t err_code) { MY_LOGI_MQTT(TAG, "Ping error occurred: %d", err_code); } // 更新回调结构体 esp_ping_callbacks_t cbs = { .on_ping_success = on_ping_success, .on_ping_timeout = on_ping_timeout, .on_ping_end = on_ping_end, .on_ping_error = on_ping_error, .cb_args = NULL}; - 检查资源释放逻辑:确保每次Ping会话无论成功失败,
esp_ping_delete_session和信号量都被正确释放,避免Socket资源泄漏。 - 调整Ping参数合理性:当前调用的
PingIp(192.168.1.23, 2, 100, 2000)中,间隔100ms小于超时2000ms,可能导致前一个Ping包未回复就发送下一个,尝试将间隔调整为大于超时时间,验证是否还出现错误。
内容的提问来源于stack exchange,提问作者scorona85
相关产品推荐
相关产品推荐

