socket-example: Add tcp client example for multiple interfaces

This commit is contained in:
Liu Han 2019-12-04 18:27:28 +08:00 committed by David Cermak
parent be3b6b7cb8
commit 547210f7a5
8 changed files with 322 additions and 0 deletions

View file

@ -0,0 +1,10 @@
# 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.5)
# (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)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(tcp_client_multiple)

View file

@ -0,0 +1,11 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := tcp_client_multiple
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk

View file

@ -0,0 +1,133 @@
# Multiple Ethernet Example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
## Overview
This example demonstrates basic usage of Ethernet interface and WiFi station together. The workflow of the example could be as follow:
1. Connects to both WiFi and Ethernet using common-connect component
2. Starts two tasks, one for each interface to resolve configured host name and connect to it periodically
3. Connection to host endpoint is handled by:
- creating a socket as TCP client
- binding it to the related interface (Ethernet of WiFi)
- send and receive a trivial HTTP request and response
If you have a new multiple interface application to go (for example, connect to IoT cloud via Ethernet and WiFi), try this as a basic template, then add your own code.
## How to use example
### Hardware Required
To run this example, you need to have one ESP32 development board integrated with an Ethernet interface, for example, ESP32-Ethernet-Kit, or just connect your ESP32-DevkitC board to a breakout board which features RMII Ethernet PHY.
### Configure the project
Enter project configuration by `idf.py menuconfig` (or `make menuconfig` if using legacy GNU Make build system) and navigate into:
* `Example Connection Configuration` menu to choose the connection details:
- Enter SSID and password for WiFi connection
- Set Ethernet type and configuration for Ethernet connection
- Note that the project is preconfigured to have both WiFi and Ethernet interface enabled by default
- See the [README.md](../../README.md) for more details about common example connection component
* `Example Configuration` menu:
- Set host name and port for the tcp_client to connect to
### Build and Flash
Run `idf.py -p PORT flash monitor` to build and flash the project..
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```bash
I (695) example_connect: Connecting to DavidsAP...
I (795) phy: phy_version: 4180, cb3948e, Sep 12 2019, 16:39:13, 0, 0
I (795) wifi:mode : sta (30:ae:a4:c6:b4:f8)
W (795) event: handler already registered, overwriting
I (815) esp_eth.netif.glue: 30:ae:a4:c6:b4:fb
I (815) esp_eth.netif.glue: ethernet attached to netif
I (825) example_connect: Waiting for IP(s)
I (1525) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:1
I (2295) wifi:state: init -> auth (b0)
I (2295) wifi:state: auth -> assoc (0)
I (2305) wifi:state: assoc -> run (10)
I (2315) wifi:connected with DavidsAP, aid = 2, channel 6, BW20, bssid = 16:f7:28:37:58:36
I (2315) wifi:security type: 3, phy: bgn, rssi: -35
I (2315) wifi:pm start, type: 1
I (2325) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (3125) esp_netif_handlers: example_connect: sta ip: 192.168.2.15, mask: 255.255.255.0, gw: 192.168.2.1
I (3125) example_connect: Interface desciption example_connect: sta
I (3135) example_connect: Interface "example_connect: sta" got IPv4 address: 192.168.2.15
I (3625) example_connect: Interface "example_connect: sta" got IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4f8, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (4825) example_connect: Ethernet Link Up
I (5625) esp_netif_handlers: example_connect: eth ip: 192.168.32.148, mask: 255.255.252.0, gw: 192.168.32.3
I (5625) example_connect: Interface desciption example_connect: eth
I (5635) example_connect: Interface "example_connect: eth" got IPv4 address: 192.168.32.148
I (6625) example_connect: Interface "example_connect: eth" got IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4fb, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6625) example_connect: Connected to example_connect: eth
I (6635) example_connect: - IPv4 address: 192.168.32.148
I (6635) example_connect: - IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4fbtype: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6645) example_connect: Connected to example_connect: sta
I (6655) example_connect: - IPv4 address: 192.168.2.15
I (6655) example_connect: - IPv6 address: fe80:0000:0000:0000:32ae:a4ff:fec6:b4f8type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (6675) example_connect: Connected to Ethernet
I (6675) tcp_client_multiple: netif described as "sta" corresponds to esp-netif ptr:0x3ffba3ac
I (6675) tcp_client_multiple: netif described as "eth" corresponds to esp-netif ptr:0x3ffc608c
I (6895) tcp_client_multiple: "example_connect: eth" Socket created
I (6895) tcp_client_multiple: "example_connect: sta" Socket created
I (6895) tcp_client_multiple: "example_connect: eth" Successfully connected
I (6905) tcp_client_multiple: "example_connect: sta" Successfully connected
I (6965) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
I (6965) tcp_client_multiple: HTTP/1.1 200 OK
Date: Thu, 23 Apr 2020 07:02:58 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html;
I (6965) tcp_client_multiple: "example_connect: sta" Received Data 127 bytes
I (6985) tcp_client_multiple: HTTP/1.1 200 OK
Date: Thu, 23 Apr 2020 07:02:58 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html;
I (7675) tcp_client_multiple: "example_connect: eth" Socket created
I (7675) tcp_client_multiple: "example_connect: eth" Successfully connected
I (7695) tcp_client_multiple: "example_connect: sta" Socket created
I (7705) tcp_client_multiple: "example_connect: sta" Successfully connected
I (7735) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
I (7735) tcp_client_multiple: HTTP/1.1 200 OK
Date: Thu, 23 Apr 2020 07:02:59 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html;
I (7955) tcp_client_multiple: "example_connect: sta" Received Data 127 bytes
I (7955) tcp_client_multiple: HTTP/1.1 200 OK
Date: Thu, 23 Apr 2020 07:02:59 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html;
I (8445) tcp_client_multiple: "example_connect: eth" Socket created
I (8445) tcp_client_multiple: "example_connect: eth" Successfully connected
I (8505) tcp_client_multiple: "example_connect: eth" Received Data 127 bytes
I (8505) tcp_client_multiple: HTTP/1.1 200 OK
Date: Thu, 23 Apr 2020 07:03:00 GMT
Expires: -1
Cache-Control: private, max-age=0
Content-Type: text/html;
I (8675) tcp_client_multiple: "example_connect: sta" Socket created
```
## Troubleshooting
* When connecting using Ethernet, please consult troubleshooting described in [Ethernet common readme](../../../ethernet/README.md)
or [Ethernet documentation](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_eth.html).
If using Ethernet for the first time, it is recommended to start with the [Ethernet example readme](../../../ethernet/basic/README.md), which contains instructions for connecting and configuring the PHY.
Once Ethernet example obtains IP address successfully, proceed to this example.
* When connecting using Wi-Fi, please refer to the WiFi examples in [examples/wifi/getting_started/](../wifi/getting_started).

View file

@ -0,0 +1,2 @@
idf_component_register(SRCS "tcp_client_multiple.c"
INCLUDE_DIRS ".")

View file

@ -0,0 +1,16 @@
menu "Example Configuration"
config EXAMPLE_HOST_NAME
string "Host Name"
default "baidu.com"
help
host name
config EXAMPLE_HOST_PORT
int "Host Port"
default 80
range 0 65535
help
host port
endmenu

View file

@ -0,0 +1,4 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,144 @@
/* multiple network interface 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 <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_netif.h"
#include "esp_eth.h"
#include "esp_event.h"
#include "esp_log.h"
#include "sdkconfig.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include <sys/socket.h>
#include <netdb.h>
#include "protocol_examples_common.h"
static const char *TAG = "tcp_client_multiple";
#define HOST_NAME CONFIG_EXAMPLE_HOST_NAME
#define HOST_IP_PORT CONFIG_EXAMPLE_HOST_PORT
static const char *payload = "GET / HTTP/1.1\r\n\r\n";
static void app_multiple_handle(esp_ip4_addr_t *ip4_addr, esp_netif_t *esp_netif)
{
esp_netif_ip_info_t ip;
char rx_buffer[128] = {0};
const char *netif_name = esp_netif_get_desc(esp_netif);
/* Create a socket */
int sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
if (sock < 0) {
ESP_LOGE(TAG, "\"%s\" Unable to create socket: errno %d", netif_name, errno);
goto app_multiple_handle_fail;
}
ESP_LOGI(TAG, "\"%s\" Socket created", netif_name);
/* Bind local IP of the network interface */
memset(&ip, 0, sizeof(esp_netif_ip_info_t));
ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif, &ip));
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = ip.ip.addr;
int ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr));
if (ret < 0) {
ESP_LOGE(TAG, "\"%s\" Unable to bind socket: errno %d", netif_name, errno);
goto app_multiple_handle_fail;
}
/* Connect to the host by the network interface */
struct sockaddr_in destAddr;
destAddr.sin_addr.s_addr = ip4_addr->addr;
destAddr.sin_family = AF_INET;
destAddr.sin_port = htons(HOST_IP_PORT);
ret = connect(sock, (struct sockaddr *)&destAddr, sizeof(destAddr));
if (ret != 0) {
ESP_LOGE(TAG, "\"%s\" Socket unable to connect: errno %d", netif_name, errno);
goto app_multiple_handle_fail;
}
ESP_LOGI(TAG, "\"%s\" Successfully connected", netif_name);
ret = send(sock, payload, strlen(payload), 0);
if (ret < 0) {
ESP_LOGE(TAG, "\"%s\" Error occured during sending: errno %d", netif_name, errno);
goto app_multiple_handle_fail;
}
ret = recv(sock, rx_buffer, sizeof(rx_buffer) - 1, 0);
if (ret < 0) {
ESP_LOGE(TAG, "\"%s\" Error occured during receiving: errno %d", netif_name, errno);
} else if (ret > 0){
rx_buffer[ret] = 0; // Null-terminate whatever we received and treat like a string
ESP_LOGI(TAG, "\"%s\" Received Data %d bytes", netif_name, ret);
ESP_LOGI(TAG, "%s", rx_buffer);
} else {
ESP_LOGE(TAG, "\"%s\" Closed connection during receiving", netif_name);
}
app_multiple_handle_fail:
close(sock);
}
static void app_connection_task(void *pvParameters)
{
esp_ip4_addr_t ip4_addr;
const char *netif_desc = pvParameters;
esp_netif_t *netif = get_example_netif_from_desc(netif_desc);
ESP_LOGD(TAG, "netif described as \"%s\" corresponds to esp-netif ptr:%p", netif_desc, netif);
while(netif) {
/* Wait for the host name to get */
const struct addrinfo hints = {
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
};
struct addrinfo *res;
int err = getaddrinfo(HOST_NAME, NULL, &hints, &res);
if(err != 0 || res == NULL) {
ESP_LOGE(TAG, "DNS lookup failed err=%d res=%p", err, res);
break;
}
memcpy(&ip4_addr, &((struct sockaddr_in *)(res->ai_addr))->sin_addr, sizeof(ip4_addr));
freeaddrinfo(res);
/* Connect the host using the corresponding network interface */
app_multiple_handle(&ip4_addr, netif);
vTaskDelay(500 / portTICK_PERIOD_MS);
}
ESP_LOGE(TAG, "%s with netif desc:%s Failed! exiting", __func__, netif_desc);
vTaskDelete(NULL);
}
void app_main(void)
{
//Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
ESP_ERROR_CHECK(example_connect());
xTaskCreate(&app_connection_task, "app_ethernet_task", 4096, "eth", 5, NULL);
xTaskCreate(&app_connection_task, "app_wifi_task", 4096, "sta", 5, NULL);
}

View file

@ -0,0 +1,2 @@
CONFIG_EXAMPLE_CONNECT_WIFI=y
CONFIG_EXAMPLE_CONNECT_ETHERNET=y