Merge branch 'examples/tcp_client_linux_support' into 'master'

tcp_client example: support for Linux target.

Closes IDF-5636

See merge request espressif/esp-idf!19203
pull/9656/head
David Čermák 2022-08-18 12:40:37 +08:00
commit fbc32c0312
15 zmienionych plików z 475 dodań i 85 usunięć

Wyświetl plik

@ -238,6 +238,8 @@ examples/protocols/sockets/tcp_client:
- if: IDF_TARGET != "esp32"
temporary: true
reason: lack of runners
enable:
- if: INCLUDE_DEFAULT == 1 or IDF_TARGET == "linux"
examples/protocols/sockets/tcp_client_multi_net:
disable:

Wyświetl plik

@ -1,10 +1,14 @@
# The following five lines of boilerplate have to be in your project's
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
if(${IDF_TARGET} STREQUAL "linux")
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IDF_PATH}/tools/mocks/freertos/")
set(COMPONENTS main)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
else()
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
endif()
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tcp_client)

Wyświetl plik

@ -1,5 +1,5 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- |
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-S2 | ESP32-S3 | Linux |
| ----------------- | ----- | -------- | -------- | -------- | -------- | ----- |
# TCP Client example
@ -8,13 +8,38 @@
The application creates a TCP socket and tries to connect to the server with predefined IP address and port number. When a connection is successfully established, the application sends message and waits for the answer. After the server's reply, application prints received reply as ASCII text, waits for 2 seconds and sends another message.
## How to use example
## Configure the project
This example can be configured to run on ESP32 and Linux target to communicate over IPv4 and IPv6.
```
idf.py menuconfig
```
Set following parameters under ```Example Configuration``` Options:
* Set `IP version` of example to be IPV4 or IPV6.
* Set `IPV4 Address` in case your chose IP version IPV4 above.
* Set `IPV6 Address` in case your chose IP version IPV6 above.
* For IPv6 there's an additional option for ```Interface selection```.
* Enter the name of the interface to explicitely establish communication over a specific interface.
* On selecting ```Auto``` the example will find the first interface with an IPv6 address and use it.
* Set `Port` number that represents remote port the example will connect to.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following command.
## How to use example:
In order to create TCP server that communicates with TCP Client example, choose one of the following options.
There are many host-side tools which can be used to interact with the UDP/TCP server/client.
One command line tool is [netcat](http://netcat.sourceforge.net) which can send and receive many kinds of packets.
Note: please replace `192.168.0.167 3333` with desired IPV4/IPV6 address (displayed in monitor console) and port number in the following command.
In addition to those tools, simple Python scripts can be found under sockets/scripts directory. Every script is designed to interact with one of the examples.
@ -24,35 +49,24 @@ nc -l 192.168.0.167 3333
```
### Python scripts
Script example_test.py could be used as a counter part to the tcp-client project, ip protocol name (IPv4 or IPv6) shall be stated as argument. Example:
Script example_test.py could be used as a counter part to the tcp-client project, ip protocol name (IPv4 or IPv6) shall be stated as argument.
Note that this script is used in automated tests, as well, so the IDF test framework packages need to be imported.
Please run the following commands to configure the terminal to execute the script.
```
export PYTHONPATH="$IDF_PATH/tools:$IDF_PATH/tools/ci/python_packages"
python -m pip install -r $IDF_PATH/tools/ci/python_packages/ttfw_idf/requirements.txt
```
Example:
```
python example_test.py IPv4
```
Note that this script is used in automated tests, as well, so the IDF test framework packages need to be imported;
please add `$IDF_PATH/tools/ci/python_packages` to `PYTHONPATH`.
## Hardware Required
This example can be run on any commonly available ESP32 development board.
This example can also run on any Linux environment.
## Configure the project
```
idf.py menuconfig
```
Set following parameters under Example Configuration Options:
* Set `IP version` of example to be IPV4 or IPV6.
* Set `IPV4 Address` in case your chose IP version IPV4 above.
* Set `IPV6 Address` in case your chose IP version IPV6 above.
* Set `Port` number that represents remote port the example will connect to.
Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
## Build and Flash

Wyświetl plik

@ -0,0 +1,6 @@
if(${IDF_TARGET} STREQUAL "linux")
idf_component_register(SRCS
esp_stubs/esp_stubs.c
INCLUDE_DIRS . include/stubs
REQUIRES main)
endif()

Wyświetl plik

@ -0,0 +1,45 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdlib.h>
#include "esp_err.h"
#include "esp_log.h"
extern void app_main(void);
void _esp_error_check_failed(esp_err_t rc, const char *file, int line, const char *function, const char *expression)
{
ESP_LOGE("ESP_ERROR_CHECK", "Failed with esp_err_t: 0x%x", rc);
ESP_LOGE("ESP_ERROR_CHECK", "Expression: %s", expression);
ESP_LOGE("ESP_ERROR_CHECK", "Functions: %s %s(%d)", function, file, line);
abort();
}
esp_err_t esp_event_loop_create_default(void)
{
return ESP_OK;
}
esp_err_t esp_netif_init(void)
{
return ESP_OK;
}
esp_err_t example_connect(void)
{
return ESP_OK;
}
esp_err_t nvs_flash_init(void)
{
return ESP_OK;
}
int main()
{
app_main();
return 0;
}

Wyświetl plik

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "esp_err.h"
esp_err_t esp_event_loop_create_default(void);

Wyświetl plik

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <sys/ioctl.h>
#include <net/if.h>
#include <ifaddrs.h>
#include "esp_err.h"
esp_err_t esp_netif_init(void);

Wyświetl plik

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "esp_err.h"
esp_err_t nvs_flash_init(void);

Wyświetl plik

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "esp_err.h"
esp_err_t example_connect(void);

Wyświetl plik

@ -1,2 +1,13 @@
idf_component_register(SRCS "tcp_client.c"
INCLUDE_DIRS ".")
if(${IDF_TARGET} STREQUAL "linux")
set(requires esp_stubs)
endif()
if("${CONFIG_EXAMPLE_IPV4}" STREQUAL y)
set(tcp_client_ip tcp_client_v4.c)
else()
set(tcp_client_ip tcp_client_v6.c)
endif()
idf_component_register(SRCS "tcp_client_main.c" "${tcp_client_ip}"
INCLUDE_DIRS "."
REQUIRES ${requires})

Wyświetl plik

@ -35,6 +35,26 @@ menu "Example Configuration"
help
The remote port to which the client example will connect to.
choice EXAMPLE_INTERFACE
prompt "Interface selection"
depends on EXAMPLE_IPV6
help
Example can use either "Auto" or "User specified".
config EXAMPLE_IFACE_AUTO
bool "Auto"
config EXAMPLE_USER_SPECIFIED_IFACE
bool "User specified interface"
endchoice
config EXAMPLE_USER_SPECIFIED_IFACE_NAME
string "User specified interface name"
default "st1"
depends on EXAMPLE_USER_SPECIFIED_IFACE
help
This interface will be used for communication.
choice EXAMPLE_SOCKET_IP_INPUT
prompt "Socket example source"
default EXAMPLE_SOCKET_IP_INPUT_STRING

Wyświetl plik

@ -0,0 +1,27 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "nvs_flash.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "esp_event.h"
extern void tcp_client(void);
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
tcp_client();
}

Wyświetl plik

@ -1,33 +1,24 @@
/* 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.
*/
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "sdkconfig.h"
#include <string.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h> // struct addrinfo
#include <arpa/inet.h>
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
#if defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
#include "addr_from_stdin.h"
#include "lwip/err.h"
#include "lwip/sockets.h"
#endif
#if defined(CONFIG_EXAMPLE_IPV4)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV4_ADDR
#elif defined(CONFIG_EXAMPLE_IPV6)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
#define HOST_IP_ADDR ""
#endif
@ -36,7 +27,8 @@
static const char *TAG = "example";
static const char *payload = "Message from ESP32 ";
static void tcp_client_task(void *pvParameters)
void tcp_client(void)
{
char rx_buffer[128];
char host_ip[] = HOST_IP_ADDR;
@ -46,23 +38,16 @@ static void tcp_client_task(void *pvParameters)
while (1) {
#if defined(CONFIG_EXAMPLE_IPV4)
struct sockaddr_in dest_addr;
dest_addr.sin_addr.s_addr = inet_addr(host_ip);
inet_pton(AF_INET, host_ip, &dest_addr.sin_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, &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_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
@ -70,7 +55,7 @@ static void tcp_client_task(void *pvParameters)
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr_in6));
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
@ -96,8 +81,6 @@ static void tcp_client_task(void *pvParameters)
ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
ESP_LOGI(TAG, "%s", rx_buffer);
}
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
if (sock != -1) {
@ -106,20 +89,4 @@ static void tcp_client_task(void *pvParameters)
close(sock);
}
}
vTaskDelete(NULL);
}
void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(tcp_client_task, "tcp_client", 4096, NULL, 5, NULL);
}

Wyświetl plik

@ -0,0 +1,255 @@
/*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include "sdkconfig.h"
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h> // struct addrinfo
#include <arpa/inet.h>
#include "esp_netif.h"
#include "esp_log.h"
#if defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
#include "addr_from_stdin.h"
#endif
#if defined(CONFIG_EXAMPLE_IPV6_ADDR)
#define HOST_IP_ADDR CONFIG_EXAMPLE_IPV6_ADDR
#else
#define HOST_IP_ADDR ""
#endif
#define PORT CONFIG_EXAMPLE_PORT
static const char *TAG = "example";
static const char *payload = "Message from ESP32 ";
#if defined(CONFIG_IDF_TARGET_LINUX)
// Checks for Global address, Unique Unicast(RFC4193) and link-local address.
#define ip6_addr_isglobal(ip6addr) ((((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xe0000000UL)) & htonl(0x20000000UL)) || \
(((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xff000000UL)) & htonl(0xfc000000UL)) || \
(((ip6addr)->sin6_addr.s6_addr[0] & htonl(0xff000000UL)) & htonl(0xfe800000UL)))
/**
* @brief In case of Auto mode returns the interface name with a valid IPv6 address or
* In case the user has specified interface, validates and returns the interface name.
*
* @param[out] interface Name of the interface in as a string.
*
* @return 0 incase of success.
*/
static int get_src_iface(char *interface)
{
struct ifaddrs *ifap, *ifa;
char src_addr_str[INET6_ADDRSTRLEN];
if (getifaddrs(&ifap) == -1) {
ESP_LOGE(TAG, "getifaddrs failed");
return -1;
}
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
#if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
if (0 == strcmp(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE_NAME, ifa->ifa_name)) {
strcpy(interface, ifa->ifa_name);
freeifaddrs(ifap);
ESP_LOGI(TAG, "Interface: %s", interface);
return 0;
}
#else
strcpy(interface, ifa->ifa_name);
getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), src_addr_str,
sizeof(src_addr_str), NULL, 0, NI_NUMERICHOST);
struct sockaddr_in6 *src_addr = (struct sockaddr_in6 *) ifa->ifa_addr;
inet_ntop(AF_INET6, &(src_addr->sin6_addr), src_addr_str, INET6_ADDRSTRLEN);
if (ip6_addr_isglobal(src_addr)) {
//Return as we have the source address
freeifaddrs(ifap);
ESP_LOGI(TAG, "Interface: %s", interface);
return 0;
}
#endif // #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
}
}
freeifaddrs(ifap);
return -1;
}
#else
static esp_netif_t *get_esp_netif_from_iface(char *interface_i)
{
esp_netif_t *netif = NULL;
esp_err_t ret = ESP_FAIL;
char iface[10];
// Get interface details and own global ipv6 address
for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {
netif = esp_netif_next(netif);
ret = esp_netif_get_netif_impl_name(netif, iface);
if ((ESP_FAIL == ret) || (NULL == netif)) {
ESP_LOGE(TAG, "No interface available");
return NULL;
}
if (0 == strcmp(interface_i, iface)) {
return netif;
}
}
return NULL;
}
/**
* @brief In case of Auto mode returns the interface name with a valid IPv6 address or
* In case the user has specified interface, validates and returns the interface name.
*
* @param[out] interface Name of the interface in as a string.
*
* @return 0 incase of success.
*/
static int get_src_iface(char *interface)
{
esp_netif_t *netif = NULL;
esp_err_t ret = ESP_FAIL;
int ip6_addrs_count = 0;
esp_ip6_addr_t ip6[LWIP_IPV6_NUM_ADDRESSES];
// Get interface details and own global ipv6 address
for (int i = 0; i < esp_netif_get_nr_of_ifs(); ++i) {
netif = esp_netif_next(netif);
ret = esp_netif_get_netif_impl_name(netif, interface);
if ((ESP_FAIL == ret) || (NULL == netif)) {
ESP_LOGE(TAG, "No interface available");
return -1;
}
#if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
if (!strcmp(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE_NAME, interface)) {
ESP_LOGI(TAG, "Interface: %s", interface);
return 0;
}
#else
ip6_addrs_count = esp_netif_get_all_ip6(netif, ip6);
for (int j = 0; j < ip6_addrs_count; ++j) {
esp_ip6_addr_type_t ipv6_type = esp_netif_ip6_get_addr_type(&(ip6[j]));
if ((ESP_IP6_ADDR_IS_GLOBAL == ipv6_type) ||
(ESP_IP6_ADDR_IS_UNIQUE_LOCAL == ipv6_type) ||
(ESP_IP6_ADDR_IS_LINK_LOCAL == ipv6_type)) {
// Break as we have the source address
ESP_LOGI(TAG, "Interface: %s", interface);
return 0;
}
}
#endif // #if defined(CONFIG_EXAMPLE_USER_SPECIFIED_IFACE)
}
return -1;
}
#endif // #if defined(CONFIG_IDF_TARGET_LINUX)
void tcp_client(void)
{
char rx_buffer[128];
char host_ip[] = HOST_IP_ADDR;
int addr_family = 0;
int ip_protocol = 0;
char interface[10];
#if defined(CONFIG_IDF_TARGET_LINUX)
struct ifreq ifr;
#else
esp_netif_t *netif = NULL;
#endif
while (1) {
#if defined(CONFIG_EXAMPLE_IPV6)
struct sockaddr_in6 dest_addr = { 0 };
inet_pton(AF_INET6, host_ip, &dest_addr.sin6_addr);
dest_addr.sin6_family = AF_INET6;
dest_addr.sin6_port = htons(PORT);
addr_family = AF_INET6;
ip_protocol = IPPROTO_TCP;
#elif defined(CONFIG_EXAMPLE_SOCKET_IP_INPUT_STDIN)
struct sockaddr_storage dest_addr = { 0 };
ESP_ERROR_CHECK(get_addr_from_stdin(PORT, SOCK_STREAM, &ip_protocol, &addr_family, &dest_addr));
#endif
int sock = socket(addr_family, SOCK_STREAM, ip_protocol);
if (sock < 0) {
ESP_LOGE(TAG, "Unable to create socket: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Socket created, connecting to %s:%d", host_ip, PORT);
if (0 != get_src_iface(interface)) {
ESP_LOGE(TAG, "Interface: Unavailable\n");
break;
}
#if defined(CONFIG_IDF_TARGET_LINUX)
memset (&ifr, 0, sizeof(ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl (sock, SIOCGIFINDEX, &ifr) < 0) {
ESP_LOGE(TAG, "ioctl() failed to find interface ");
break;
}
#if defined(CONFIG_EXAMPLE_IPV6)
dest_addr.sin6_scope_id = ifr.ifr_ifindex;
ESP_LOGI(TAG, "Interface index: %d\n", dest_addr.sin6_scope_id);
#endif
#else
if (NULL == (netif = get_esp_netif_from_iface(interface))) {
ESP_LOGE(TAG, "Failed to find interface ");
break;
}
#if defined(CONFIG_EXAMPLE_IPV6)
dest_addr.sin6_scope_id = esp_netif_get_netif_impl_index(netif);
ESP_LOGI(TAG, "Interface index: %d\n", dest_addr.sin6_scope_id);
#endif
#endif
int err = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
if (err != 0) {
ESP_LOGE(TAG, "Socket unable to connect: errno %d", errno);
break;
}
ESP_LOGI(TAG, "Successfully connected");
while (1) {
int err = send(sock, payload, strlen(payload), 0);
if (err < 0) {
ESP_LOGE(TAG, "Error occurred during sending: errno %d", errno);
break;
}
int len = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
// Error occurred during receiving
if (len < 0) {
ESP_LOGE(TAG, "recv failed: errno %d", errno);
break;
}
// Data received
else {
rx_buffer[len] = 0; // Null-terminate whatever we received and treat like a string
ESP_LOGI(TAG, "Received %d bytes from %s:", len, host_ip);
ESP_LOGI(TAG, "%s", rx_buffer);
}
}
if (sock != -1) {
ESP_LOGE(TAG, "Shutting down socket and restarting...");
shutdown(sock, 0);
close(sock);
}
}
}

Wyświetl plik

@ -0,0 +1,4 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) Project Minimal Configuration
#
# CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER is not set