ESP8266 - AP mode TCP Server multi-client link

tags: ESP8266

First, record

  1. Use the official RTOS_SDK 3.2 version, example is ESP8266_RTOS_SDK \ Examples \ Protocols \ Sockets \ TCP_SERVER
  2. In the official example, there is a problem. If the client is connected, turn off the connection, 8266Server terminal will not stop unable to create socket error
    Cause: After the client close, only the client fd is closed, and the FD of the Server Listen is not closed, and the big loop is jumped out, causing the SOCK of the Server side, resulting in errors.
    Repair method: Add a large for loop after listen
  3. I have changed here to compatibility with non-blocking methods, using SELECT to operate
    Here is a non-blocking implementation method:Non-blocking implementation

Special attention:

(1). The attribute of .fd may not perform NO_BLOCK configuration
(2). Struct TimeVal TV; TV.tv_usec Can't be less than 1000, otherwise the system crashes will collapse this unit is US

/* 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 "esp_system.h"
#include "esp_log.h"
#include "esp_netif.h"
#include "esp_event.h"
#include "protocol_examples_common.h"
#include "nvs.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sockets.h"
#include "lwip/sys.h"
#include <lwip/netdb.h>

#include "xzh_wifi.h"

#define PORT 10000

static const char *TAG = "example";

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");
		
		
		#if 0
		for(;;)
		{

	#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);
				//close(listen_sock);
				//vTaskDelay(500/portTICK_PERIOD_MS);
			}
		}
		#else
			
		
		fd_set readfds, testfds; 
		
		int client_sockfd;
		uint client_len;
		
		struct sockaddr_in sourceAddr;
		
		int result; 
		
		FD_ZERO(&readfds); 
		FD_SET(listen_sock, &readfds);// Add the server side Socket to the collection

		while(1) 
		{
			char ch; 
			int fd; 
			int nread; 
			testfds = readfds;// In the descriptor set COPY to the SELECT query query, SELECT will modify it, so be sure to use variables separately. 
			//printf("server waiting\n"); 
	 
			/ * Unlink blocking, and test file descriptor change * /
			struct timeval tv;
			tv.tv_sec = 0;
			tv.tv_usec = 10*1000; // 10MS Can't be less than 1000, otherwise the system will collapse
			result = select(FD_SETSIZE, &testfds, (fd_set *)0,(fd_set *)0, (struct timeval *) &tv); // fd_setsize: System default maximum file descriptor
			// Result = SELECT (FD_SETSIZE, & TESTFDS, (fd_set *) 0, (FD_SET *) 0, (Struct Timeval *) & 0); // If TV is 0 completely blocked
			if(result < 1) 
			{ 
				//perror("server5"); 
				//exit(1); 
			} 
	 
			/ * Scan all file descriptors * /
			for(fd = 0; fd < FD_SETSIZE; fd++) 
			{
				/ * Find related file descriptor * /
				if(FD_ISSET(fd,&testfds)) 
				{ 
				  / * Determine if it is a server socket, which is represented as a client request connection. * /
					if(fd == listen_sock) 
					{ 
						client_len = sizeof(sourceAddr); 
						client_sockfd = accept(listen_sock, 
						(struct sockaddr *)&sourceAddr, &client_len); 
						FD_SET(client_sockfd, &readfds);// Add the client socket to the collection
						printf("adding client on fd %d\n", client_sockfd); 
					} 
					/ * When there is a data request in the client socket * /
					else 
					{ 
						#if 0
						ioctl(fd, FIONREAD, &nread);// obtain the amount of data to NREAD
						/ * The customer data request is complete, close the socket, clear the corresponding descriptor from the collection * /
						if(nread == 0) 
						{ 
							//close(fd); 
							// fd_clr (fd, & readfds); // Remove the close FD
							//printf("removing client on fd %d\n", fd); 
						} 
						/ * Handle customer data request * /
						else 
						{ 
							read(fd, &ch, 1); 
							//sleep(5); 
							printf("serving client on fd %d\n", fd); 
							ch++; 
							write(fd, &ch, 1); 
						} 
						#else
						char rx_buffer[128];
						int len = recv(fd, rx_buffer, sizeof(rx_buffer) - 1, 0);
						if (len < 0) 
						{
							ESP_LOGE(TAG, "recv failed: errno %d", errno);
							//break;
						}
						// Connection closed
						else if (len == 0) 
						{
							ESP_LOGI(TAG, "Connection closed");
							close(fd); 
							FD_CLR(fd, &readfds); / / Remove the close FD
							printf("serving client on fd %d\n", fd); 
							//break;
						}
						else
						{
							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);		
						}
						#endif
						
						
					} 
				} 
			} 
		}

		#endif
    }
    vTaskDelete(NULL);
}

void app_main()
{
    ESP_ERROR_CHECK(nvs_flash_init());
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    //ESP_ERROR_CHECK(example_connect());
	xzh_wifi_ap_init("XZH_ESP8266","xuanzihao");
	
	

    xTaskCreate(tcp_server_task, "tcp_server", 4096, NULL, 5, NULL);
}


About the AP mode, note that XeventGroupWaitBits in xzh_wifi_ap_init is used to block, wait for AP to build (WiFi_Event_ap_start event occurs)

// AP section

static void ip_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    switch (event_id) {
        case IP_EVENT_AP_STAIPASSIGNED:
            //xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
			ESP_LOGI(TAG, "IP_EVENT_AP_STAIPASSIGNED\r\n \r\n");
            break;
        default:
            break;
    }
    return;
}


static void wifi_event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    switch (event_id) {
		case WIFI_EVENT_AP_STACONNECTED:
		{
			wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
					 MAC2STR(event->mac), event->aid);
			break;
		}
		case WIFI_EVENT_AP_STADISCONNECTED:
		{
			wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
			ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
					 MAC2STR(event->mac), event->aid);
			break;
		}
		case WIFI_EVENT_AP_START:
		{
			ESP_LOGI(TAG, "WIFI_EVENT_AP_START\r\n \r\n");
			xEventGroupSetBits(s_connect_event_group, GOT_IPV4_BIT);
			break;
		}
        default:
            break;
    }
    return;
}


esp_err_t xzh_set_ap_info(const char *ssid, const char *passwd)
{
    strncpy(s_connection_name, ssid, sizeof(s_connection_name));
    strncpy(s_connection_passwd, passwd, sizeof(s_connection_passwd));
	
    wifi_config_t wifi_config = { 0 };

    strncpy((char *)&wifi_config.ap.ssid, s_connection_name, 32);
    strncpy((char *)&wifi_config.ap.password, s_connection_passwd, 64);
	
	wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;

   // ESP_LOGI(TAG, "Connecting to %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_AP, &wifi_config));

    return ESP_OK;
}

esp_err_t xzh_wifi_ap_init(const char *ssid, const char *passwd)
{
    if (s_connect_event_group != NULL) {
        return ESP_ERR_INVALID_STATE;
    }

    s_connect_event_group = xEventGroupCreate();
	

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    //ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &on_wifi_disconnect, NULL));
    //ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &on_got_ip, NULL));  
    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
	
    ESP_ERROR_CHECK(esp_wifi_set_storage(WIFI_STORAGE_RAM));
	

	
    wifi_config_t wifi_config = { 0 };
	
	

    strncpy((char *)&wifi_config.ap.ssid, ssid, 32);
    strncpy((char *)&wifi_config.ap.password, passwd, 64);
	
	wifi_config.ap.authmode = WIFI_AUTH_WPA2_PSK;
	
	wifi_config.ap.max_connection = 2;

    ESP_LOGI(TAG, "SSID:%s PASS:%s", wifi_config.ap.ssid,wifi_config.ap.password);
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP));
    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
	
    ESP_ERROR_CHECK(esp_wifi_start());
	
	xEventGroupWaitBits(s_connect_event_group, CONNECTED_BITS, true, true, portMAX_DELAY);

	return ESP_OK;

}

Intelligent Recommendation

esp8266 TCP Client STA mode

Because what the embedded course does, I want to use esp8266 to send the image obtained by the camera on the development board to the computer. So I learned a bit by referring to the example on the pu...

ESP-AT Practice: ESP32 checks the AP mode and transmitted data from TCP Client and TCP Server

need: ESP32 check AP mode Other equipment Connect an ESP32 AP ESP32 connection TCP Server ESP32 is transmitted to TCP Server as TCP Client Test instruction: Test steps: 1 Android mobile phone can use ...

STM32F103C8T6 Drive ESP8266 Transfer Module (1) -The HAL Library Drive Code Detailed Explanation of Module AP Mode+TCP Client (CUBEMX Project)

1.stm32 Drive the ESP8266 module The ESP8266 module used by the author is a module developed by the point atomic, which turns the communication interface into a serial port. The introduction of the ES...

ESP8266 Development Notes (3) TCP Sever Connection in AP mode

One year ago, I would like to make a simple smart home product yourself on ESP8266, and then facing the internship and graduation work, I went to Zigbee. I have been to the releare, I think about this...

ESP8266 turns on AP mode

Today we are doing an instance of ESP8266 to open hotspot mode! ! If there is a problem with the program debugging, please leave a message! !...

More Recommendation

ESP8266--STA/AP mode

AP/STA mode of ESP8266 AP: The wireless access point is the creator of a wireless network and the central node of the network. Generally, a wireless router used in a home or office is an AP. STA: Each...

ESP8266 AP mode

ESP8266 AP mode ESP8266 has three working modes, namely wireless access point mode (AP), wireless terminal mode (STA mode) and hybrid mode (a combination of the above two modes). This section introduc...

ESP8266 Learning --ap Mode

AP Mode content os_memset Code head File Macro Global variable Initialize WiFi function [ESP8266_AP_INIT] Software timing callback function [os_timer_1_cb] user_init Overall code Summary frame content...

ESP8266 tcp passthrough AP + STA

AP Establishing WIFI, STA accepts the connection, mutual transfer serial data and TCP       STA Connection WIFI, connected AP, the serial data to each other      Test Example transmitting abc / s...

ESP8266 NONOS SDK——AP+TCP

First import the espconn.h file. The use of this file also needs to add #include "ip_addr.h" inside the header file, otherwise the espconn header file will report an error that the ip_addr t...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top