Forum: Mikrocontroller und Digitale Elektronik ESP8266 - SPIFFS streamFile will nicht richtig auf Android aber auf PC


von Timmo H. (masterfx)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich baue gerade ein Webinterface auf dem ESP und Teste es vorrangig 
erstmal auf dem PC via Chrome 67.0.3396.99 (aber auch auf Edge) und 
alles hat bisher gut funktioniert.
Dann wollte ich das Interface mal auf meinem Android Handy mit der 
neusten Chrome Version 68.0.3440.91 (war mit der alten aber auch so) und 
da laden die Seiten mit etwas größeren Bildern (> ~20 kB) nicht. Der 
Content liegt auf dem SPIFFS.
Also habe ich einfach mal nur das Bild geladen 
"http://192.168.0.120/test.jpg"; welches 80 kB groß ist. Unter Chrome auf 
PC dauert es rund 390ms bis es geladen ist (laut Chrome Devtools). Rufe 
ich die selbe Adresse auf dem Android Handy auf, läd er sich tot. Auf 
dem Terminal mache ich zudem noch eine Ausgabe welches File angefordert 
wurde " handleFileRead: xyz" und eine Ausgabe wenn es gesendet wurde 
"Sent file: xyz". Und auch auf dem Terminal sieht man dass das "Sent 
file: xyz" sehr viel später kommt als wenn man es über PC aufruft.

Ich benutze PlatformIO mit Espressif 8266 1.7.3.

Der Code ist überschaubar (siehe Anhang).
Der ESP verbindet sich mit meinem WLAN, der PC ist via RJ45 
angeschlossen und das Handy natürlich auch via WLAN am Router.

Jemand eine Idee woran das liegen kann?

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich würde die Netzwerk-Kommunikation mit Wireshark untersuchen.

von Timmo H. (masterfx)


Lesenswert?

Gibt es leider nicht für Android

von Stefan F. (Gast)


Lesenswert?

Du sollst das Wireshark ja auch auf deinem PC laufen lassen.

Manche Router erlauben es, den Verkehr zwischen ESP und Smartphone 
mitschnüffeln. Bei manchen ist es einstellbar. Wenn du dieses Glück hast 
wäre das auf jeden Fall die einfachste Option.

Wenn dein Router das nicht erlaubt, kannst du den ESP mit der Ethernet 
Buchse deines PC verbinden und das Smartphone mit der WLAN 
Schnittstelle. Dann ist dein PC der Router zwischen dieses beiden 
Geräten und dann kann der auch den ganzen Netzwerkverkehr mitlesen.

Dazu gibt es Tutorials im Netz.

Außerdem gibt es Alternativen zu Wireshark, die auf Android laufen: 
https://techwiser.com/wireshark-alternatives-for-android/ Ich würde mein 
Smartphone allerdings nicht rooten.

von Timmo H. (masterfx)


Lesenswert?

Stefanus F. schrieb:
> kannst du den ESP mit der Ethernet
> Buchse deines PC verbinden
Cool, wie geht das? Der ESP hat nur WLAN...
Selbst wenn ich meinem PC via WLAN mit dem Router verbinde geht es ja 
auch problemlos. Ich könnte meinen PC natürlich zum AP machen aber das 
ist mir ehrlich gesagt alles zu viel Aufwand. Ich vermute einfach einen 
Bug im ESP-Core oder so. Ich werde dann mal weiter googeln. Irgendwas 
scheint das Handy halt anders zu machen als der PC

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

> Cool, wie geht das? Der ESP hat nur WLAN...
Denk nach! Natürlich mit einer WLAN Brücke oder einem WLAN Router.

> Ich könnte meinen PC natürlich zum AP machen
Auch das wäre eine Möglichkeit. Vielleicht sogar die bessere weil du 
dann keine zusätzliche Hardware bnenötigst.

> Ich vermute einfach einen Bug im ESP-Core oder so.
Vermuten nützt leider nichts, Wissen auch nicht. Du brauchst einen 
Workaround - sofern der Fehler nicht in deinem eigenen Code steckt.

> Irgendwas scheint das Handy halt anders zu machen als der PC
Eben das ist der spannende Punkt. Mit einem Netzwerk Trace findest du 
den Knackpunkt (vielleicht) und dann kannst um den herum bauen.

Mir ist gerade noch eine Lösung eingefallen: Du kannst Android x86 als 
virtuelle Maschine auf deinem PC laufen lassen. Falls der Fehler darin 
nicht auftritt, kannst du das Google SDK herunterladen, da ist ein 
Android ARM Emulator drin.

von Sascha W. (sascha-w)


Lesenswert?

Hallo Timmo,

du solltest auf den Async Webserver wechseln, der einfache Server hat 
ein Problem wenn man mehrere Seiten gleichzeitig anfragt.
Und da der Browser gern mal noch das Favicon laden will hängt das Teil 
dann.

Sascha

von Timmo H. (masterfx)


Lesenswert?

Hallo Sascha,
danke für den Hinweis. Dennoch frage ich mich warum es dann auf dem PC 
einwandfrei funktioniert, auch wenn die Seite mehrere Bilder enthält.
Ich meine selbst wenn ich als Adresse nur das jpg oder bmp angebe... 
dann lädt er ja nichts anderes parallel. Gucke ich mir die http header 
mal an passiert da auch nicht wirklich mehr als es müsste
1
GET /test.bmp HTTP/1.1
2
Host: 192.168.0.120
3
Connection: keep-alive
4
Cache-Control: max-age=0
5
Upgrade-Insecure-Requests: 1
6
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36
7
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
8
Accept-Encoding: gzip, deflate
9
Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7
10
11
HTTP/1.1 200 OK
12
Content-Type: image/bmp
13
Content-Length: 90054
14
Connection: close

von Timmo H. (masterfx)


Lesenswert?

Mhh, habe gerade noch mal die Size ausgeben lassen.
1
bool handleFileRead(String path) { // send the right file to the client (if it exists)
2
  Serial.println("handleFileRead: " + path);
3
  if (path.endsWith("/")) path += "index.html";          // If a folder is requested, send the index file
4
  String contentType = getContentType(path);             // Get the MIME type
5
  String pathWithGz = path + ".gz";
6
  if (SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists, either as a compressed archive, or normal
7
    if (SPIFFS.exists(pathWithGz))                         // If there's a compressed version available
8
      path += ".gz";                                         // Use the compressed verion
9
    File file = SPIFFS.open(path, "r");                    // Open the file
10
    size_t sent = server.streamFile(file, contentType);    // Send it to the client
11
    file.close();                                          // Close the file again
12
    Serial.println(String("\tSent file: ") + path);
13
    Serial.println(String("\tSent size: ") + sent);
14
    return true;
15
    
16
  }
17
  Serial.println(String("\tFile Not Found: ") + path);   // If the file doesn't exist, return false
18
  return false;
19
}
Wenn ich das bmp von PC lade:
1
handleFileRead: /test.bmp
2
        Sent file: /test.bmp
3
        Sent size: 90054
Vom Handy (dauert aber ewig)
1
handleFileRead: /test.bmp
2
        Sent file: /test.bmp
3
        Sent size: 2920
Komisch, 2920 ist genau 2x 1460 (MTU)

von Timmo H. (masterfx)


Lesenswert?

Okay nach weiterem Googlen scheint es ein Bug zu sein.
Jedoch funzt suggerierte Lösung nicht
1
    int size = file.size();
2
    
3
    char buf[1024];
4
    while(size > 0) {
5
      size_t len = std::min((int)(sizeof(buf) - 1), size);
6
      file.read((uint8_t *)buf, len);
7
      server.client().write((const char*)buf, len);
8
      size -= len;
9
    }
bei mir nicht.

von Stefanus F. (Gast)


Lesenswert?

Ich schätze du hast die aktuelle Plugin Version 2.4.2 verwendet. 
Versuche es mal mit der älteren 2.3.0.

von Timmo H. (masterfx)


Lesenswert?

Tatsache mit 2.3.0 gehts. Dauert zwar ca. 10x so lang, aber es geht... 
"Danke"

von Stefan F. (Gast)


Lesenswert?

In selbst geschriebenen Client Anwendungen (auch Apps) kannst du die 
Socket-Option TCP_NODELAY beim Verbindungsaufbau setzen. Dann läuft die 
Übertragung schneller.

von Timmo H. (masterfx)


Lesenswert?

Interessant.
2.3.0:  return _currentClient.write(file, HTTP_DOWNLOAD_UNIT_SIZE);
2.4.1:  return _currentClient.write(file);

Wobei die HTTP_DOWNLOAD_UNIT_SIZE = 1460 ist. Warum haben die das raus 
genommen? Klar scheint schneller zu sein wenn die MTU größer ist, aber 
wenns nicht immer geht ist halt auch nervig

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.