Skip to content

ESP8266WebServer: The problem with frequent simultaneous connections (early response closing, not timeout) #8904

Closed
@jjsuwa-sys3175

Description

@jjsuwa-sys3175

Basic Infos

  • This issue complies with the issue POLICY doc.
  • I have read the documentation at readthedocs and the issue is not addressed there.
  • I have tested that the issue is present in current master branch (aka latest git).
  • I have searched the issue tracker for a similar issue.
  • If there is a stack dump, I have decoded it.
  • I have filled out all fields below.

Platform

Settings in IDE

  • Module: [Generic ESP8266 Module]
  • Flash Mode: [qio]
  • Flash Size: [4MB]
  • lwip Variant: [v2 Higher Bandwidth]
  • Reset Method: [nodemcu]
  • Flash Frequency: [80Mhz]
  • CPU Frequency: [160MHz]
  • Upload Using: [SERIAL]
  • Upload Speed: [512000]

Problem Description

A moderate rate of unexpected HTTP (or socket) disconnections/timeouts is observed when trying to connect to the ESP8266WebServer at a high frequency.
But other HTTP servers belonging to the same WiFi do not see such disconnections/timeouts.

MCVE Sketch

#define WIFI_SSID     "YOUR-WIFI-SSID"
#define WIFI_PASSWORD "YOUR-WIFI-PASSWORD"

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer webServer(80);

void setup() {
  Serial.begin(74880);
  delay(1000);
  Serial.print(F("\n\nconnecting to WiFi"));
  WiFi.mode(WIFI_STA);
  WiFi.begin(F(WIFI_SSID), F(WIFI_PASSWORD));
  for (; ; Serial.print('.'), delay(333))
    if (WiFi.status() == WL_CONNECTED)
      break;
  Serial.println(F(", done."));
  String addr = WiFi.localIP().toString();
  webServer.onNotFound([]() {
    webServer.send(404);
  });
  webServer.on(F("/"), HTTP_GET, []() {
    StreamString s;
    s.reserve(40);
    s.print(F("http://"));
    WiFi.localIP().printTo(s);
    s.print(F("/index.html"));
    webServer.sendHeader(F("Location"), s);
    webServer.send(302);
  });
  Serial.printf_P(PSTR("webServer: http://%s/\n"), addr.c_str());
  webServer.on(F("/index.html"), HTTP_GET, []() {
    webServer.send(200, F("text/html"), F("<!DOCTYPE html><html>"
                                          "<head><title>WiFi HTTP server</title></head>"
                                          "<body><h1>WiFi HTTP server</h1><p>hello world</p></body>"
                                          "</html>"));
  });
  Serial.printf_P(PSTR("webServer: http://%s/index.html\n"), addr.c_str());
  webServer.on(F("/blob.bin"), HTTP_GET, []() {
    size_t length = (ESP.random() & 4095) + 4096;
    auto buffer = new uint8_t[length];
    ESP.random(buffer, length);
    webServer.send(200, PSTR("application/octet-stream"), buffer, length);
    delete[] buffer;
  });
  Serial.printf_P(PSTR("webServer: http://%s/blob.bin\n"), addr.c_str());
  webServer.begin();
}

void loop() {
  webServer.handleClient();
}

Detailed Procedure

  1. Build the above MVCE and upload it to the chip.
  2. After the chip reboots and connects to your WiFi, you should get a serial output similar to:
connecting to WiFi................, done.
webServer: http://192.168.2.83/
webServer: http://192.168.2.83/index.html
webServer: http://192.168.2.83/blob.bin
  1. Now, let's use the HTTP load test program "siege" from a linux PC belonging to the same WiFi network to send high-frequency HTTP requests to the chip. First, write something like this in a text file:
http://192.168.2.83/
http://192.168.2.83/index.html
http://192.168.2.83/blob.bin
  1. Next, run "siege" in benchmark mode for a some time (a one hour, for example). You'll probably see some alerts in the near future...
vboxuser@Bullseye64:/tmp$ siege -bt 1H -f siege.txt > /dev/null 
** SIEGE 4.0.7
** Preparing 25 concurrent users for battle.
The server is now under siege...
[alert] socket: select and discovered it's not ready sock.c:384: Connection timed out
[alert] socket: read check timed out(30) sock.c:273: Connection timed out
[alert] socket: select and discovered it's not ready sock.c:384: Connection timed out
[alert] socket: read check timed out(30) sock.c:273: Connection timed out
...
  1. Just to be clear, other HTTP servers (Apache, nginx, or even a simple server written in python) don't behave this way. Also, changing the "lwip Variant" setting does the same.
  2. After an hour the "siege" summary looks roughly like this:
Lifting the server siege...
Transactions:                 559940 hits
Availability:                  99.81 %
Elapsed time:                3599.58 secs
Data transferred:             855.06 MB
Response time:                  0.10 secs
Transaction rate:             155.56 trans/sec
Throughput:                     0.24 MB/sec
Concurrency:                   15.94
Successful transactions:      560229
Failed transactions:            1088
Longest transaction:           15.92
Shortest transaction:           0.00

Whether or not a failure rate of 0.19% is appropriate is left to the judgment of each person...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions