ESP8266 als Webserver hängt bei mehreren Requests

Hallo zusammen,
vielleicht kennt sich ja jemand mit meinem Problem aus und hat Lust mir zu helfen.

als kurze Einleitung zu meinem Problem:
ich habe meinen Esp8266-01 mittels des "HelloServer"-Beispiels als Webserver aufgesetzt.
Dieser nutzt auch den Flashspeicher.
Ruft man die IP des Webservers auf, gelangt man auf eine selbstgeschriebene Internetseite,
die 6 sehr kleine Fotos beinhaltet.

Es klappte eigentlich alles gut, bis auf Folgendes, womit ich auch zu meinem Problem kommen möchte:

Die 6 Fotos, welche max. jeweils 4kB groß sind, werden beim Aufruf der Webseite beim Webserver(dem ESP) via get-request angefragt.
Dies fange ich ab, handle die Anfragen entsprechend und streame die Fotos.

[...]
  server.on("/klein.jpg", klein);
  server.on("/2xklein.jpg", zxklein);
  server.on("/normal.jpg", normal);
  server.on("/2xnormal.jpg", zxnormal);
  server.on("/gross.jpg", gross);
  server.on("/2xgross.jpg", zxgross);
[...]

Sind es nur 3 Fotos, klappt alles top und die Seite lädt innerhalb von ca 3 Sekunden.
Sobald ich mehr auf der Webseite einbinde, kommt er ins straucheln und braucht sehr lange, um die Seite zu laden; im besten Fall werden manche der Bilder nicht richtig angezeigt, im schlechteren Fall wird ein "wdt-reset" ausgelöst, der ESP hängt sich auf.
(wdt-reset beutet WatchDogTimer-reset wenn ich mich nicht irre)

Für mich scheinen es also die vielen(>3) requests, die für die Bilder "rausgejagt" werden, zu sein,
die dem ESP nicht gefallen.
Oder könnte es mit dem Zugriff auf den Speicher zu tun haben ?

Meine Frage ist: Kennt jemand das Problem und kann mir weiterhelden, wie man dies am klügsten löst ?

Freue mich sehr auf (eure) Antworten!

Viele Grüße!

Der ESP kann nur 4 TCP Slots gleichzeitig bedienen. (der Browser serialisiert das)
Auch braucht die WiFi Task dafür Zeit.
Du solltest dafür Sorge tragen, dass die Task auch die Zeit bekommt.
Also in deine Auslieferung ein paar yield() oder delay(0) einbauen.

Leitsatz:
Jeder Schleife ihr yield(). (zumindest bei lang laufenden Schleifen)

Danke für den hilfreichen Tipp, das mit den 4 TCP-Slots wusste ich zum Beispiel garnicht.
Kannst du mir nocheinmal erläutern, was mit der browserseitigen Serialisierung gemeint ist ?
Hängt dieser alle Requests hintereinander und diese werden in 4-er "Paketen", da 4 TCP-Slots max. möglich sind, abgearbeitet ?

Bei vielen Browsern kann man einstellen, wie viele Sockets er gleichzeitig aufzumachen versucht. Oft ist 8 die Default Einstellung.
Und ja, logischer weise macht er das immer nacheinander.
Leider wird er daran häufig versagen, z.B. wenn schon 4 auf sind.
Naja...
Kann man nix dran machen....
Ist auch kein Drama, sollte trotzdem gehen.

Nagut:
Was man tun könnte, wäre einen weiteren Webserver bereit stellen.
z.B. einen Raspberry mit Apache und PHP.
Dann alle konstanten Ressourcen, wie Bilder, JavaScript, css, usw. von diesem holen.

Danke !
Hatte gehofft man könne es ohne Workaround lösen,
also irgendwie die Slots verwalten..
Habe es fürs erste so gelöst, dass ich die Bilder ausgelagert habe,
auf einen anderen Server.
Er lädt nun blitzschnell die Seite auf der meine Steuerung/"Gui" läuft, dennoch bin ich nicht hundertprozentig befriedigt, was das Crashen mit den 4 TCP Slots angeht.
Naja ich rede mir ein, dass er ursprünglich auch nie als Server gedacht war und dafür macht er sich als Server schon erstaunlich gut ^^

was das Crashen mit den 4 TCP Slots angeht.

Was meinst du damit?

Klar ist er mit max 4 Sockets nicht allzu fix, aber "crashen"?
Das liegt woanders dran!

Nun, wenn ich beispielsweise 5 verschiedene Dateien in einer Website einbinde(kleine Bilder, css-files etc.) und meinen ESP als Webserver laufen lasse wird die Indexdatei nicht mehr korrekt angezeigt.
Die Website lädt sehr lange und diese wird nach ca 30 Sekunden nicht richtig angezeigt.
Bei 4 oder 5 Bildern äussert sich das ganze so, dass diese eben nicht mehr geladen werden.

In einem anderen Beispiel was ich gefunden habe, scheint aber eine Website die auf Jquery zurückgreift problemlos zu laden.
ich habe den HTML-Code der Indexdatei, die auf dem ESP im Beispiel geladen wird angesehen und hier werden auch einige Scripte und css dateien "requestet".

Hier ist mal das Beispiel:
http://adityatannu.com/blog/post/2016/01/24/ESP8266-Websockets-demo-using-NeoPixels.html
(Files kann man angucken, wenn man auf die jeweiligen Überschriften klickt, eine Anmeldung ist nicht erforderlich)

Darf ich vllt. nochmal meine Code posten und jemand guckt mit drüber, wo ich Fehler gemacht habe?

Ich habe hier nochmal ein möglichst simples Beispiel gebastelt, bei dem ebenfalls das Problem auftritt.
In den Weiten des WWWs habe ich eine ähnliche Fragestellung gefunden, bei der die Lösung war, dass auch ein Header mit Content-Length und Conten-Type sowie ein "Connection Close" befehl gesendet werden müssten.

Dies wird in diesem Code aber von der Funktion "server.stream" erledigt, oder irre ich mich da ?

Hier mal das leicht verändertes "ESP8266 Webserver BeispieL", mit einer internetseite, die 2 Scripte und 2 css Dateien für Jquery laden sollte:

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include "FS.h"


ESP8266WebServer server(80);

const char* ssid = "meinWlan";
const char* password = "meinWLanPW";


//Anfang automatischer File-Handler

bool loadFromSpiffs(String path) {
  String dataType = "text/plain";
  if (path.endsWith("/")) path += "index.htm";

  if (path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  else if (path.endsWith(".html")) dataType = "text/html";
  else if (path.endsWith(".css")) dataType = "text/css";
  else if (path.endsWith(".js"))  dataType = "application/javascript";
  else if (path.endsWith(".png")) dataType = "image/png";
  else if (path.endsWith(".gif")) dataType = "image/gif";
  else if (path.endsWith(".jpg")) dataType = "image/jpeg";
  else if (path.endsWith(".ico")) dataType = "image/x-icon";
  else if (path.endsWith(".xml")) dataType = "text/xml";
  else if (path.endsWith(".pdf")) dataType = "application/pdf";
  else if (path.endsWith(".zip")) dataType = "application/zip";
  
  File dataFile = SPIFFS.open(path.c_str(), "r");
  if (server.hasArg("download")) dataType = "application/octet-stream";
  if (server.streamFile(dataFile, dataType) != dataFile.size()) {
  }
  
  if (!dataFile) {
    dataFile.close();
    yield();
    return false;
  }
  else{
    dataFile.close();
     yield();
    return true;
  }
}
//Ende automatischer File-Handler

void handleRoot() {
  Serial.println("Htmldatei requestet");
  loadFromSpiffs("/index.html");
  yield();
  Serial.println("indexDatei übertragen");
  //server.send(200, "text/plain", "okiDoki");
  yield();
  
}

void jpgLoader(String bildname) {
    bildname="/"+bildname;
    if (loadFromSpiffs(bildname)) {
      yield();
      delay(20);      
      server.send(200, "text/plain", "Bild gefunden");
      Serial.println("Bild "+bildname+" ist da");
      yield();   
  }
  else {
    server.send(404, "text/plain", "keine solche Datei gefunden");
    Serial.println("Bild "+bildname+" nicht gefunden");
  }
  delay(2);
  Serial.println("ende JPGLoader");
};

void css1() {
  if (loadFromSpiffs("/src/css/jqueryMS.css")) {
  Serial.println("css1");
  yield();
  }
  else {
  Serial.println("css1 negativ");  
  yield();
  }
};

void css2() {
  if (loadFromSpiffs("/src/css/jqueryMobileTheme.css")) {
  Serial.println("css2");
  yield();
  }
  else {
  Serial.println("css2 negativ");  
  } 
};

void lib1() {
  if (loadFromSpiffs("/lib/jquery164.js")) {
  Serial.println("lib1");
  yield();
  }
  else {
  Serial.println("css2 negativ");  
  } 
};

void lib2() {
  if (loadFromSpiffs("lib/jqueryMob.js")) {
  Serial.println("lib2");
  yield();
  }
  else {
  Serial.println("css2 negativ");  
  } 
};
 
void formatierung(){
  Serial.println("Formatting SPIFFS:");
  while(!SPIFFS.format()){
  };
  Serial.println("FORMATIERUNG ERFOLGREICH BEENDET"); 
  }

void handleNotFound() {

  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);

}


void setup(void) {
 
  Serial.begin(115200);
  SPIFFS.begin();
  
  WiFi.begin(ssid, password);

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());


  if (MDNS.begin("esp8266")) {
    Serial.println("MDNS responder started");
  }

  //  server.on("/diag", HTTP_GET,diags);
  server.on("/", handleRoot);
  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });
  server.on("/src/css/jqueryMobileTheme.css", css2);
  server.on("/src/css/jqueryMS.css", css1);
  server.on("/lib/jquery164.js", lib1);
  server.on("lib/jqueryMob.js", lib2);
  server.onNotFound(handleNotFound);
  server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void) {
  server.handleClient();
}

Es dauert ~60 Sekunden bis die Seite da ist.

Ich bin mir ziemlich sicher, dass ich irgendwo vergesse etwas an den Websiteaufrufenden Client (in meinem Fall der Firefox) zu schicken, um die Verbindung abzuschließen und damit das Ganze zu beschleunigen.

Das SketchArchiv habe ich ebenfalls angehängt.

Hat jemand Ideen ?? Findet jemand den Fehler ? Ich bin leider mit meinem Latein am Ende :frowning:

BeispielFehlersuche-161217b.zip (163 KB)

oder irre ich mich da ?

Das kannst du prüfen!

Fast jeder moderne Browser bietet die Möglichkeit sich die HTTP Header anzeigen zu lassen.

Genau das habe ich mir auch gedacht und gerade getan.
Es wird die Content-Größe, der Content-Inhalte und danach auch ein Connnection-Close gesendet.
Hieran kann es nicht liegen..
Ich habe ein Beispiel gefunden, bei dem auch der ESP sowie auch das ESP8266Webserver Beispiel genutzt werden und auch die Jquery lib eingebunden wurde.

Hier dauert das laden ca 3 Sekunden, obwohl ca 6-7 Dateien requestet werden.
(hier der Link: http://adityatannu.com/blog/post/2016/01/24/ESP8266-Websockets-demo-using-NeoPixels.html )

Verstehe nicht, wieso es bei mir so lange dauert... :frowning:

Edit: Was ich noch rausfinden konnte ist, dass es auf dem Handy "nur" 20 Sekunden dauert(unter Android mit FireFox mobile), bis die Seite da ist; was gegenüber den durchschnittlich 95 Sekunden am normalen Rechner (Auch mittels Firefox) schonmal eine Steigerung ist.

Scheint also auch am Browser zu liegen, aber wo kann ich noch optimieren ?
Bei Anderen scheints auch schneller zu gehen, also muss es wohl an meinen Codeschnipseln liegen

Keiner 'ne Idee was ich falsch mache?

daOEKL:
Keiner 'ne Idee was ich falsch mache?

Nein!
(zumindest nicht wirklich)

Meine Glaskugel sagt:

  1. Du solltest dein Flash mit 80MHz betreiben
  2. Du solltest das Flash im QIO Mode betreiben
  3. Die Prozessorgeschwindigkeit auf 160MHz hoch setzen (die Änderung im Code dabei nicht vergessen)

Hi Combie,
freue mich immer, wenn jemand antwortet.
Du scheinst einiges an Erfahrung und Ahnung mitzubingen, ich bin momentan noch dabei, diese zu sammeln.
Wieso so gehässig ?
Falls ich Infos vorenthalten habe, die fehlen, weise mich doch vielleicht einfach darauf hin ?
Ich bin ja hier um zu lernen und für Kritik offen..

Ich benutze die Arduino IDE V1.6.5.
Ich benutze ein Wemos D1-mini Board mit ESP8266.

Wärst du in der Lage mir zu helfen ?
Falls ja, was müsstest du dafür wissen ?
Den gesamten Sketch habe ich oben hochgeladen.

Wo stelle ich denn die Geschwindigkeit für den Flash ein ?!
Wo kann ich die Konfiguration für QIO/DIO Mode setzen ?
Wo setzt man die Prozessorgeschwindigkeit ?! Im Sketch finde ich hierzu nichts !

Wieso so gehässig ?

? ? ? ? ?
Jetzt bin ich platt.....

Ich bin verantwortlich für das, was ich sage, nicht für das, was du verstehst

Habe ich mal auf einem T-Shirt gesehen....

Wo stelle ich denn die Geschwindigkeit für den Flash ein ?!
Wo kann ich die Konfiguration für QIO/DIO Mode setzen ?
Wo setzt man die Prozessorgeschwindigkeit ?!

Im Menu der Arduino IDE.
Da wo du das Board einstellst.

Wo setzt man die Prozessorgeschwindigkeit ?

void setup()
{

   system_update_cpu_freq(SYS_CPU_160MHZ);


  // dein Kram
}

Danke !
Ich hatte im Boardmanager das D1-Mini Board ausgewählt; hier waren diese Einstellungen nicht vorhanden.
Nach umstellen auf "Generic ESP8266" konnte ich diese dann sehen,
allerdingss wurden meine Erwartungen erfüllt, die Seit lädt nicht viel schneller..
DIO/QIO machen hierbei leider auch keinen Unterschied.

Es muss definitiv an der Software und den einzelnen Browsern liegen, da zwischen Firfox mobile und Firefox normal ein merklicher Unterschied von ca. einer Minute entsteht.

Habe im Netz einen Ansatz gefunden, bei dem eine Delay-Zeit in einer Config.h Datei geändert, genauer gesagt verringert werden muss.

Das werde ich heute Abend mal testen.

Entschuldige bitte, wenn ich dich falsch verstanden habe, aber dein "Meine Glaskugel sagt" suggerierte mir, dir irgendwo "vor den Kopf gestoßen" zu haben..

Entschuldige bitte, wenn ich dich falsch verstanden habe, aber dein "Meine Glaskugel sagt" suggerierte mir, dir irgendwo "vor den Kopf gestoßen" zu haben..

Alles gut....

Eigentlich wollte ich dir damit sagen, dass ich im RateModus bin.
Und das mit geringer Trefferwahrscheinlichkeit.

Entschuldige, dann habe ich dich falsch verstanden !

Mein Stand ist momentan dieser:

Das Problem liegt nicht am ESP, eher am Client:
Der Internetexplorer zaubert die Seiten ca 10mal schneller auf den Schirm.
Firefox 50.1 sowie der Chrome 55.0 brauchen sehr lange (um 90 Sekunden herum)

Ich habe über diverse Suchmaschinen hauptsächlich auf Englisch einige andere User gefunden, die das gleiche Problem zu haben scheinen.
Soweit ich es richtig verstanden habe, liegt das Problem am TCP Protokoll der jew. Betriebssysteme und des Browsers, was auch erklären würde wieso auf meinem ANDROID-Handy die Seiten schneller luden.

Stellt man in der ClientContext.h den Wert des delay(5000); // max send timeout
auf beispielsweise 5. lädt die Seite zwar fix, allerdings kommen die Dateien nicht mehr an ^^

Ich habe mich mit TCP noch nicht sonderlich viel auseinandersetzen müssen, aber was wohl die enormen Ladezeiten verursacht sind Delays die Browserseitig nach jedem Paket ausgelöst werden, scheinbar gefallen den Browsern die Pakete nicht, die sie bekommen.
Da mir das zu viel Arbeit ist und ich hierzu auch einfach noch zu wenig Erfahrung habe, behelfe ich mir fürs erste durchs Auslagern auf fremde Server.

Diskutiert wird über genau das Problem hier, falls jemand über diesen Post stolpern sollte: Slow performance of FSBrowser on Chrome and Firefox · Issue #1027 · esp8266/Arduino · GitHub (Ich hoffe das Posten dieses Links ist in Ordnung)

Die Jungs wirken auf jeden Fall fitter als ich auf dem Gebiet,
vllt. lässt sich ja eine Lösung finden.