mirror of
https://github.com/espressif/esp-idf.git
synced 2025-12-15 19:34:03 +00:00
BSD Socket examples
This commit is contained in:
6
examples/protocols/sockets/tcp_server/CMakeLists.txt
Normal file
6
examples/protocols/sockets/tcp_server/CMakeLists.txt
Normal file
@@ -0,0 +1,6 @@
|
||||
# The following five 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)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(tcp_server)
|
||||
9
examples/protocols/sockets/tcp_server/Makefile
Normal file
9
examples/protocols/sockets/tcp_server/Makefile
Normal file
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := tcp_server
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
||||
72
examples/protocols/sockets/tcp_server/README.md
Normal file
72
examples/protocols/sockets/tcp_server/README.md
Normal file
@@ -0,0 +1,72 @@
|
||||
|
||||
# TCP Server example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
The application creates a TCP socket with the specified port number and waits for a connection request from the client. After accepting a request from the client, connection between server and client is established and the application waits for some data to be received from the client. Received data are printed as ASCII text and retransmitted back to the client.
|
||||
|
||||
## How to use example
|
||||
|
||||
In order to create TCP client that communicates with TCP server 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.
|
||||
|
||||
### TCP client using netcat
|
||||
```
|
||||
nc 192.168.0.167 3333
|
||||
```
|
||||
|
||||
### Python scripts
|
||||
Script tcpclient.py contains configuration for port number, IP version (IPv4 or IPv6) and IP address that has to be altered to match the values used by the application. Example:
|
||||
|
||||
```
|
||||
PORT = 3333;
|
||||
IP_VERSION = 'IPv4'
|
||||
IPV4 = '192.168.0.167'
|
||||
IPV6 = 'FE80::32AE:A4FF:FE80:5288'
|
||||
```
|
||||
|
||||
## Hardware Required
|
||||
|
||||
This example can be run on any commonly available ESP32 development board.
|
||||
|
||||
## Configure the project
|
||||
|
||||
```
|
||||
make menuconfig
|
||||
```
|
||||
|
||||
Set following parameter under Serial Flasher Options:
|
||||
|
||||
* Set `Default serial port`.
|
||||
|
||||
Set following parameters under Example Configuration Options:
|
||||
|
||||
* Set `WiFi SSID` of the Router (Access-Point).
|
||||
|
||||
* Set `WiFi Password` of the Router (Access-Point).
|
||||
|
||||
* Set `IP version` of the example to be IPV4 or IPV6.
|
||||
|
||||
* Set `Port` number of the socket, that server example will create.
|
||||
|
||||
## Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Start server first, to receive data sent from the client (application).
|
||||
@@ -0,0 +1,4 @@
|
||||
set(COMPONENT_SRCS "tcp_server.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
||||
36
examples/protocols/sockets/tcp_server/main/Kconfig.projbuild
Normal file
36
examples/protocols/sockets/tcp_server/main/Kconfig.projbuild
Normal file
@@ -0,0 +1,36 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config WIFI_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config WIFI_PASSWORD
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
Can be left blank if the network has no security set.
|
||||
|
||||
choice EXAMPLE_IP_MODE
|
||||
prompt "IP Version"
|
||||
help
|
||||
Example can use either IPV4 or IPV6.
|
||||
|
||||
config EXAMPLE_IPV4
|
||||
bool "IPV4"
|
||||
|
||||
config EXAMPLE_IPV6
|
||||
bool "IPV6"
|
||||
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_PORT
|
||||
int "Port"
|
||||
range 0 65535
|
||||
default 3333
|
||||
help
|
||||
Local port the example server will listen on.
|
||||
|
||||
endmenu
|
||||
4
examples/protocols/sockets/tcp_server/main/component.mk
Normal file
4
examples/protocols/sockets/tcp_server/main/component.mk
Normal file
@@ -0,0 +1,4 @@
|
||||
#
|
||||
# "main" pseudo-component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
212
examples/protocols/sockets/tcp_server/main/tcp_server.c
Normal file
212
examples/protocols/sockets/tcp_server/main/tcp_server.c
Normal file
@@ -0,0 +1,212 @@
|
||||
/* 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 <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_loop.h"
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include "lwip/err.h"
|
||||
#include "lwip/sockets.h"
|
||||
#include "lwip/sys.h"
|
||||
#include <lwip/netdb.h>
|
||||
|
||||
|
||||
/* 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;
|
||||
const int IPV6_GOTIP_BIT = BIT1;
|
||||
|
||||
static const char *TAG = "example";
|
||||
|
||||
static esp_err_t event_handler(void *ctx, system_event_t *event)
|
||||
{
|
||||
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:
|
||||
/* enable ipv6 */
|
||||
tcpip_adapter_create_ip6_linklocal(TCPIP_ADAPTER_IF_STA);
|
||||
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:
|
||||
/* This is a workaround as ESP32 WiFi libs don't currently auto-reassociate. */
|
||||
esp_wifi_connect();
|
||||
xEventGroupClearBits(wifi_event_group, IPV4_GOTIP_BIT);
|
||||
xEventGroupClearBits(wifi_event_group, IPV6_GOTIP_BIT);
|
||||
break;
|
||||
case SYSTEM_EVENT_AP_STA_GOT_IP6:
|
||||
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);
|
||||
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()
|
||||
{
|
||||
uint32_t bits = IPV4_GOTIP_BIT | IPV6_GOTIP_BIT ;
|
||||
|
||||
ESP_LOGI(TAG, "Waiting for AP connection...");
|
||||
xEventGroupWaitBits(wifi_event_group, bits, false, true, portMAX_DELAY);
|
||||
ESP_LOGI(TAG, "Connected to AP");
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
struct sockaddr_in6 sourceAddr; // Large enough for both IPv4 or IPv6
|
||||
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 {
|
||||
// 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
void app_main()
|
||||
{
|
||||
ESP_ERROR_CHECK( nvs_flash_init() );
|
||||
initialise_wifi();
|
||||
wait_for_ip();
|
||||
|
||||
xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
|
||||
}
|
||||
Reference in New Issue
Block a user