笔者最近在测试时,突然遇到了以下错误:
网上看过一些帖子,要么就是只提出遇到了相同问题,但没有解答。如:transport_base: Poll timeout or error, errno=Connection already in progress - ESP32 Forum
要么就是和本问题类似,但不完全相同的问题。如:
TRANSPORT_BASE: poll_read select error 113, errno = Software caused connection abort, fd = 54: cannot recover from this - ESP32 Forum
要么就是虽然给出了一定的分析和一些建议的解决方法,但都不适合当前所遇问题,并且也没有更深层面的分析。如:
咨询乐鑫的技术支持,至今没有反馈……
既然没有更好的办法,那么就只能自力更生。深入到代码,对此问题进行跟踪和分析。看看到底是Wi-Fi模组自身的性能问题,还是自己的代码逻辑问题。
首先,要找到错误提示出自于哪个文件的哪个函数中。在ESP-IDF的工程源码(注意:不是新建工程的,要ESP-IDF的安装路径或者组件库路径中查找,如:C:\Espressif\frameworks\esp-idf-v5.2.1)。
经过搜索,最终定位到是在components\components\tcp_transport\transport_ssl.c的ssl_write函数中。代码如下:
static int ssl_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll;
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->sockfd, timeout_ms);
return poll;
}
int ret = esp_tls_conn_write(ssl->tls, (const unsigned char *) buffer, len);
if (ret < 0) {
ESP_LOGE(TAG, "esp_tls_conn_write error, errno=%s", strerror(errno));
esp_tls_error_handle_t esp_tls_error_handle;
if (esp_tls_get_error_handle(ssl->tls, &esp_tls_error_handle) == ESP_OK) {
esp_transport_set_errors(t, esp_tls_error_handle);
} else {
ESP_LOGE(TAG, "Error in obtaining the error handle");
}
}
return ret;
}
实际上在components\components\tcp_transport\transport_ssl.c文件中还有一处相同打印,在tcp_write函数中,该函数代码如下:
static int tcp_write(esp_transport_handle_t t, const char *buffer, int len, int timeout_ms)
{
int poll;
transport_esp_tls_t *ssl = ssl_get_context_data(t);
if ((poll = esp_transport_poll_write(t, timeout_ms)) <= 0) {
ESP_LOGW(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d", strerror(errno), ssl->sockfd, timeout_ms);
return poll;
}
int ret = send(ssl->sockfd, (const unsigned char *) buffer, len, 0);
if (ret < 0) {
ESP_LOGE(TAG, "tcp_write error, errno=%s", strerror(errno));
esp_transport_capture_errno(t, errno);
}
return ret;
}
可以看到,两个函数(ssl_write和tcp_write)还是比较相似的,都是先调用esp_transport_poll_write函数进行判断,而后一个调用esp_tls_conn_write函数,另一个调用(经典的)send函数。由于笔者的MQTT是MQTTs即带证书认证的,因此应该走的是ssl_write函数,后文书也会重点围绕ssl_write函数展开分析和讲解。
对于ssl_write函数及其相关上下文的解析,请看下回。