开发板:esp-32
问题描述:
我使用两台esp32,不断重复以下步骤:连接wifi--》创建TCP server --》作为TCP client向另一台esp32发送数据 --》 断开 wifi
经过五轮左右循环后出现以下两个报错:
Code: Select all
TCP SERVER: Unable to create socket: errno 23
TCP client: Unable to create socket: errno 23
Code: Select all
/**
* @brief 发送 wifi 数据, wifi 发送数据指令格式:
* |-- 目的地址长度(1 byte) --|-- 目的地址(n bytes) --|-- 信息长度(2 bytes) --|-- 目的地址长度(n bytes) --|
* @param[in] data - 发送数据内容
* @param[in] len - 发送数据内容的长度
*/
int tcpClientSendDataToRemote(uint8_t *data, const uint16_t len)
{
char host_ip[17] = {0};
int addr_family = 0;
int ip_protocol = 0;
int sendDataLen = 0;
int toWrite = len;
int written = 0;
int sock = 0;
int err = 0;
if (NULL == data || len < 11 || WifiStation.status != WIFI_STATUS_CONNECTED)
{
return -1;
}
memcpy((uint8_t *)host_ip, (uint8_t *)(data + 1), data[0]);
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;
sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0)
{
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
goto failed;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
err = setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
if (err != 0)
{
goto failed;
}
err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
if (err != 0)
{
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
goto failed;
}
ESP_LOGI(TAG, "Successfully connected");
// struct linger link;
// link.l_onoff = 1;
// link.l_linger = 5;
// err = setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&link, sizeof(struct linger));
// if (err != 0)
// {
// ESP_LOGE(TAG, "SO_LINGER errno %d", errno);
// goto failed;
// }
while (toWrite > 0)
{
// written = send(sock, (data + 1 + data[0] + 2 + (sendDataLen - toWrite)), toWrite, 0);
written = send(sock, (data + len - toWrite), toWrite, 0);
if (written < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
goto failed;
}
toWrite -= written;
}
if (sock != -1)
{
ESP_LOGW(TAG, "Shutting down socket");
printf("************ %s(%d) sock:%d\n", __func__, __LINE__, sock);
shutdown(sock, 0);
// struct linger link;
// link.l_onoff = 1;
// link.l_linger = 5;
// setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&link, sizeof(struct linger));
close(sock);
printf("************ %s(%d) sock:%d\n", __func__, __LINE__, sock);
}
return 0;
failed:
if (sock != -1)
{
printf("************ %s(%d) sock:%d\n", __func__, __LINE__, sock);
shutdown(sock, 0);
// struct linger link;
// link.l_onoff = 1;
// link.l_linger = 5;
// setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&link, sizeof(struct linger));
close(sock);
printf("************ %s(%d) sock:%d\n", __func__, __LINE__, sock);
}
return -1;
}
/**
* @brief wifi 接收任务
*/
static void tcpServeTask(void *pvParameters)
{
char addr_str[128];
int addr_family = (int)pvParameters;
int ip_protocol = 0;
int keepAlive = 1;
int keepIdle = KEEPALIVE_IDLE;
int keepInterval = KEEPALIVE_INTERVAL;
int keepCount = KEEPALIVE_COUNT;
struct sockaddr_storage dest_addr;
int err = 0;
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;
}
listen_sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (listen_sock < 0)
{
ESP_LOGE(SERVER_TAG, "Unable to create socket: errno %d", errno);
goto CLEAN_UP;
}
int opt = 1;
setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
ESP_LOGI(SERVER_TAG, "Socket created");
err = bind(listen_sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0)
{
ESP_LOGE(SERVER_TAG, "Socket unable to bind: errno %d", errno);
ESP_LOGE(SERVER_TAG, "IPPROTO: %d", addr_family);
goto CLEAN_UP;
}
ESP_LOGI(SERVER_TAG, "Socket bound, port %d", PORT);
struct linger link;
link.l_onoff = 1;
link.l_linger = 5;
err = setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, (const char*)&link, sizeof(struct linger));
if (err != 0)
{
ESP_LOGE(SERVER_TAG, "SO_LINGER errno: %d", errno);
goto CLEAN_UP;
}
ESP_LOGI(SERVER_TAG, "Start listen");
err = listen(listen_sock, 1);
if (err != 0)
{
ESP_LOGE(SERVER_TAG, "Error occurred during listen: errno %d", errno);
goto CLEAN_UP;
}
while (1)
{
ESP_LOGI(SERVER_TAG, "Socket listening");
struct sockaddr_storage source_addr; // Large enough for both IPv4 or IPv6
socklen_t addr_len = sizeof(source_addr);
int sock = accept(listen_sock, (struct sockaddr *)&source_addr, &addr_len);
if (sock < 0)
{
ESP_LOGE(SERVER_TAG, "Unable to accept connection: errno %d", errno);
goto CLEAN_UP;
}
// Set tcp keepalive option
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keepIdle, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keepInterval, sizeof(int));
setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keepCount, sizeof(int));
// Convert ip address to string
if (source_addr.ss_family == PF_INET)
{
inet_ntoa_r(((struct sockaddr_in *)&source_addr)->sin_addr, addr_str, sizeof(addr_str) - 1);
}
ESP_LOGI(SERVER_TAG, "Socket accepted ip address: %s", addr_str);
do_retransmit(sock);
shutdown(sock, 0);
// struct linger link;
// link.l_onoff = 1;
// link.l_linger = 5;
// setsockopt(sock, SOL_SOCKET, SO_LINGER, (const char*)&link, sizeof(struct linger));
close(sock);
}
CLEAN_UP:
printf("************ %s(%d) listen_sock:%d\n", __func__, __LINE__, listen_sock);
close(listen_sock);
TcpServerHandle = NULL;
vTaskDelete(NULL);
printf("************ %s(%d) listen_sock:%d\n", __func__, __LINE__, listen_sock);
}
void tcpServeTaskStartUp(void)
{
tcpServeTaskStop();
xTaskCreate(tcpServeTask, "TCP_CLIENT_TASK", 8192, (void*)AF_INET, 5, &TcpServerHandle);
}
void tcpServeTaskStop(void)
{
if (TcpServerHandle != NULL)
{
vTaskDelete(TcpServerHandle);
TcpServerHandle = NULL;
}
if (listen_sock > 0)
{
printf("************ %s(%d) listen_sock:%d\n", __func__, __LINE__, listen_sock);
close(listen_sock);
printf("************ %s(%d) listen_sock:%d\n", __func__, __LINE__, listen_sock);
listen_sock = 0;
}
}
通过打印,发现socket没有释放,于是menuconfig TCP参数,减小MSL时间,将socket数量提高到16,但依然会出现无法分配socket问题
Code: Select all
(16) Maximum active TCP Connections
(16) Maximum listening TCP Connections
[*] TCP high speed retransmissions
(12) Maximum number of retransmissions of data segments
(12) Maximum number of retransmissions of SYN segments
(1440) Maximum Segment Size (MSS)
(250) TCP timer interval(ms)
(6000) Maximum segment lifetime (MSL)
(2000) Maximum FIN segment lifetime
(5744) Default send buffer size
(5744) Default receive window size
(6) Default TCP receive mail box size
[*] Queue incoming out-of-order segments
[ ] Support sending selective acknowledgements
Pre-allocate transmit PBUF size (MSS) --->
(1500) Default TCP rto time