ESP8266 IDF RTOS 乐鑫例程 tcp_server.c断开连接后无法重新连接的解决办法。
乐鑫ESP8266 IDF 源码 tcp_server.c在ESP8266_RTOS_SDK中。
git clone --recursive https://github.com/espressif/ESP8266_RTOS_SDK.git
编译
make
下载到nodemcu中 然后运行打开串口监视器
make flash monitor
电脑端作为客户端连接nodemcu的tcp server可以成功,但断开后却无法重连,且报错:Socket unable to bind: errno 112
具体见图:
经网络搜索,在乐鑫官网论坛发现类似问题的帖子,参考改正了程序,实现了重连功能。
网址:
https://esp32.com/viewtopic.php?f=13&t=10335
帖子修改代码的截图:
修改程序后再次试验重连功能成功,截图:
现在上全部代码:
/* BSD Socket API Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event_loop.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include
/* The examples use simple WiFi configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define PORT CONFIG_EXAMPLE_PORT
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
const int IPV4_GOTIP_BIT = BIT0;
#ifdef CONFIG_EXAMPLE_IPV6
const int IPV6_GOTIP_BIT = BIT1;
#endif
static const char *TAG = "example";
static esp_err_t event_handler(void *ctx, system_event_t *event)
{
/* For accessing reason codes in case of disconnection */
system_event_info_t *info = &event->event_info;
switch (event->event_id) {
case SYSTEM_EVENT_STA_START:
esp_wifi_connect();
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_START");
break;
case SYSTEM_EVENT_STA_CONNECTED:
#ifdef CONFIG_EXAMPLE_IPV6
/* enable ipv6 */
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
#endif
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_CONNECTED");
break;
case SYSTEM_EVENT_STA_GOT_IP:
xEventGroupSetBits(wifi_event_group, IPV4_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP");
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
/*Switch to 802.11 bgn mode */
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCAL_11B | WIFI_PROTOCAL_11G | WIFI_PROTOCAL_11N);
}
esp_wifi_connect();
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
#ifdef CONFIG_EXAMPLE_IPV6
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
#endif
break;
case SYSTEM_EVENT_AP_STA_GOT_IP6:
#ifdef CONFIG_EXAMPLE_IPV6
xEventGroupSetBits(wifi_event_group, IPV6_GOTIP_BIT);
ESP_LOGI(TAG, "SYSTEM_EVENT_STA_GOT_IP6");
char *ip6 = ip6addr_ntoa(&event->event_info.got_ip6.ip6_info.ip);
ESP_LOGI(TAG, "IPv6: %s", ip6);
#endif
default:
break;
}
return ESP_OK;
}
static void initialise_wifi(void)
{
tcpip_adapter_init();
wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) );
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
wifi_config_t wifi_config = {
.sta = {
.ssid = EXAMPLE_WIFI_SSID,
.password = EXAMPLE_WIFI_PASS,
},
};
ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid);
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() );
}
static void wait_for_ip()
{
#ifdef CONFIG_EXAMPLE_IPV6
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT;
#else
uint32_t bits = IPV4_GOTIP_BIT;
#endif
ESP_LOGI(TAG, "Waiting for AP connection...");
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to AP");
}
static void print()
{
ESP_LOGI(TAG, "wait_for_ip is over!");
}
static void tcp_server_task(void *pvParameters)
{
char rx_buffer[128];
char addr_str[128];
int addr_family;
int ip_protocol;
while (1) {
#ifdef CONFIG_EXAMPLE_IPV4
struct sockaddr_in destAddr;
destAddr.sin_addr.s_addr = htonl(INADDR_ANY);
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(PORT);
addr_family = AF_INET;
ip_protocol = IPPROTO_IP;
inet_ntoa_r(destAddr.sin_addr, addr_str, sizeof(addr_str) - 1);
#else // IPV6
struct sockaddr_in6 destAddr;
bzero(&destAddr.sin6_addr.un, sizeof(destAddr.sin6_addr.un));
destAddr.sin6_family = AF_INET6;
destAddr.sin6_port = htons(PORT);
addr_family = AF_INET6;
ip_protocol = IPPROTO_IPV6;
inet6_ntoa_r(destAddr.sin6_addr, addr_str, sizeof(addr_str) - 1);
#endif
int listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (listen_sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created");
int err = bind(listen_sock, (struct sockaddr *)&destAddr, sizeof(destAddr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to bind: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket binded");
err = listen(listen_sock, 1);
if (err != 0) {
ESP_LOGE(TAG, "Error occured during listen: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket listening");
#ifdef CONFIG_EXAMPLE_IPV6
struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6
#else
struct sockaddr_in sourceAddr;
#endif
uint addrLen = sizeof(sourceAddr);
int sock = accept(listen_sock, (struct sockaddr *)&sourceAddr, &addrLen);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to accept connection: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket accepted");
while (1) {
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occured during receiving
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno);
break;
}
// Connection closed
else if (len == 0) {
ESP_LOGI(TAG, "Connection closed");
break;
}
// Data received
else {
#ifdef CONFIG_EXAMPLE_IPV6
// Get the sender's ip address as string
if (sourceAddr.sin6_family == PF_INET) {
inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
} else if (sourceAddr.sin6_family == PF_INET6) {
inet6_ntoa_r(sourceAddr.sin6_addr, addr_str, sizeof(addr_str) - 1);
}
#else
inet_ntoa_r(((struct sockaddr_in *)&sourceAddr)->sin_addr.s_addr, addr_str, sizeof(addr_str) - 1);
#endif
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 = send(sock, rx_buffer, len, 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occured during sending: errno %d", errno);
break;
}
}
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
//参考网络改动的程序
//https://esp32.com/viewtopic.php?f=13&t=10335
shutdown(listen_sock,0);//参考网络改动的程序
close(listen_sock);
vTaskDelay(5);
}
ESP_LOGI(TAG, "socket is close! ");
}
vTaskDelete(NULL);
}
void app_main()
{
ESP_ERROR_CHECK( nvs_flash_init() );
initialise_wifi();
wait_for_ip();
print();
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
}
程序里的宏定义需要根据自己的网络环境更改,在VScode中鼠标右键“转到定义中”,然后自行更改:
#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID
#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD
#define PORT CONFIG_EXAMPLE_PORT
在sdkconfig.h中修改
#define CONFIG_WIFI_SSID "HUAWEI" //网络SSID
#define CONFIG_WIFI_PASSWORD "password"//网络密码
#define CONFIG_EXAMPLE_IPV4 1
#define CONFIG_EXAMPLE_PORT 6666//端口号
在调试过程中发现有的网络调试软件并不好用,我开始使用的是名为“NetDebugTool”的软件,发现断开功能不正常,必须点击界面上的“X”才能实现断开功能。我不知道界面上的“断开”按钮是什么功能,有知道的网友请指点!
后来我使用正点原子STM32资料里的“网络调试助手”,感觉比较好。