PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : esp8266, Arduino IDE: neuer Versuch: warum wird website sofort beendet?



HaWe
20.10.2019, 21:36
hallo,
ich will nochmal einen Anlauf starten:

Board ESP-12E nodeMCU (esp8266),
Arduino Board core nodeMCU 1.0, version 2.5.2

wer kann sagen, warum die hier aufgebaute Website zum Eingeben von username und passwort unter Version 2.5.2 zwar kurz aufgebaut wird, dann aber sofort beendet wird?
Der Fehler tritt unter nodeMCU 1.0, version 2.4.0 noch NICHT auf.

Vermutlich ist ein Fehler drin versteckt, der bei der alten core Version geduldet wird, aber unter der neuen dann doch als Fehler sichtbar wird.
Nur: Wo ist der Fehler?



bool authorized=false;

void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();

//---------------------------------------
// debug
// authorized=true;

strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");

while ( client.connected() ) {
if (authorized) return;

if ( client.available() ) {
char c = client.read();

//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {
client.flush();

//now output html data header

String script = "";

script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");

// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");

client.print(script);

//stopping client
client.stop();
delay(1);
//clearing string for next read
//readString = "";
}
}
delay(1);
}
}




Website in Firefox:
(Seite wird kurz aufgebaut, dann sofort wieder weg, stattdessen Fehler-Website:

Fehler: Verbindung unterbrochen

Die Verbindung zum Server wurde zurückgesetzt, während die Seite geladen wurde.

Die Website könnte vorübergehend nicht erreichbar sein, versuchen Sie es bitte später nochmals.
Wenn Sie auch keine andere Website aufrufen können, überprüfen Sie bitte die Netzwerk-/Internetverbindung.
Wenn Ihr Computer oder Netzwerk von einer Firewall oder einem Proxy geschützt wird, stellen Sie bitte sicher,
dass Firefox auf das Internet zugreifen darf.


Serial Konsole, neuer core:


strupwd >>><<<
website_upwd>>>admin<<<
readString>>>GET /logout HTTP/1.1
GET /logout HTTP/1.1
Bei der alten core Version werden diese 4 Zeilen NICHT seriell ausgegeben, die Login-Seite steht stabil und wartet auf Eingaben.


Wer hat die rettende Idee?

Moppi
21.10.2019, 07:35
Solang eine Verbindung zum Client besteht, würde ich kein client.stop() senden. Die Disconnect-Nachricht könnte vielleicht daher kommen. Probehalber vor diesem Befehl ein großzügiges delay(x) von mehreren Sekunden einbauen. Sehen, wie sich das Verhalten dann darstellt. Wird die Seite dann aufgebaut, verschwindet aber nach ein paar Sekunden und es erscheint wieder die Disconnect-Message, dann wird es wohl am client.stop() liegen, das die Verbindung unterbricht.


MfG

Ceos
21.10.2019, 07:54
auch wenns englisch ist

https://forum.arduino.cc/index.php?topic=245829.0

da wird empfohlen auch vor dem stop den empfangspuffer zu leeren!

und das flush gehört natürlich wie Moppi schon sagte direkt vor das stop um sicher zu gehen dass alle Daten transferiert worden sind bevor man den Socket schließt

HaWe
21.10.2019, 07:56
hallo,
danke, der test hat immerhin schon funktioniert:
Die Seite wird jetzt nach delay(1000) ca. 1 sec lang angezeigt und danach dann abgebrochen mit derselben obigen Fehlermeldung.
Was kann man jetzt machen?

Ceos
21.10.2019, 08:02
ich korrigiere meine Aussage, erst flush(), dann RX leer machen, dann delay(1000), dann stop()

HaWe
21.10.2019, 08:04
ich korrigiere meine Aussage, erst flush(), dann RX leer machen, dann delay(1000), dann stop()

danke, nur verstehe ich jetzt noch nicht was genau wohin soll,
kannst du da mal bitte direkt in meinem Code korrigieren und in code tags posten?

edit: was bedeutet z.B. auch "RX leer machen"?



//stopping client
client.flush();
delay(1000); // debug
client.stop();

das macht bis jetzt noch keinen Unterschied (bricht ebenfalls wieder nach ca. 1 sec. ab, ohne delay(1000) auch wieder sofort)...



bool authorized=false;

void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();

//---------------------------------------
// debug
// authorized=true;

strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");

while ( client.connected() ) {
if (authorized) return;

if ( client.available() ) {
char c = client.read();

//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {

//now output html data header

String script = "";

script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");

// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");

client.print(script);

//stopping client
client.flush();
delay(1000); // debug
client.stop();

//clearing string for next read
//readString = "";
}
}
delay(1);
}
}

Moppi
21.10.2019, 08:18
Ich hatte nochmal bei flush() nachgelesen. Mein Verständnis war jetzt so: Es soll Zeichen, die noch nicht übertragen wurden, aus dem Puffer entfernen. Ich würde erst client.print(..), dann delay(...), dann client.flush(), dann client.stop().

HaWe
21.10.2019, 08:26
bool authorized=false;

void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();

//---------------------------------------
// debug
// authorized=true;

strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");

while ( client.connected() ) {
if (authorized) return;

if ( client.available() ) {
char c = client.read();

//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {

//now output html data header

String script = "";

script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");

// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");

client.print(script);

delay(1000); // debug
//stopping client
client.flush();
client.stop();

//clearing string for next read
//readString = "";
}
}
delay(1);
}
}

so?

das macht auch noch genau dieselben Fehler sowohl mit als auch ohne delay(1000);

Moppi
21.10.2019, 08:31
mal so versuchen:



while (client.connected()){}
client.stop();


statt




delay(1000); // debug
//stopping client
client.flush();
client.stop();






PS: ich habe glaub ich kein nodeMCU mit Version 2.5.x

Ceos
21.10.2019, 08:32
flush löst nur das senden verbleibender Bytes aus dem FIFO/internen Puffer aus (ungefähr wie beim trennen eines USB DAtenträger um keine Daten im Puffer zu verlieren)
delay kommt danach, da die daten auch erst übertragen werden müssen
dann sollte man folgende Schleife einbauen


while(client.connected()) {
while(client.available()) {
Serial.write(client.read());
}
}

und DANN erst schließen

das Serial.write() ist nur zu Debugzwecken und du kannst einfach in eine dummy variable auslesen wenn die restlichen Daten unwichtig sind, abe erstmal mit Debug Ausgabe um zu wissen ob der Browser überhaupt noch was sendet

HaWe
21.10.2019, 08:40
bool authorized=false;

void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();

//---------------------------------------
// debug
// authorized=true;

strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");

while ( client.connected() ) {
if (authorized) return;

if ( client.available() ) {
char c = client.read();

//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {

//now output html data header

String script = "";

script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");

// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");

client.print(script);
while(client.connected()) {
delay(10);
/*
while(client.available()) {
Serial.write(client.read());
}
*/
}

delay(100);
client.stop(); // edited

//clearing string for next read
//readString = "";
}
}
delay(1);
}
}

jaaa...!
das hat jetzt zum ersten Mal gefunzt! 8)
Das werde ich jetzt ausgiebig testen und dann berichten!
Tausend Dank auf jeden Fall schon einmal an euch beide!

Ceos
21.10.2019, 08:46
JETZT hast du dein client.close() allerdings auch entfernt, was zu "socketverstopfung" führen kann.

HaWe
21.10.2019, 08:54
ach so, ich dachte, der soll auch mit weg?
soll der auch direkt dahinter?

while(client.connected()) {
while(client.available()) {
Serial.write(client.read());
}
}
delay(100);
client.stop();

- - - Aktualisiert - - -

PS,
habe es mal so gemacht,
einziger "Schönheitsfehler" jetzt noch: ich muss immer 2x hintereinander auf den "Daten absenden"-Button klicken (oder ENTER-Taste), damit usrname+pwd übertragen werden, aber nach dem 2. mal klappt es jetzt (ohne client.stop() war es auch schon so).

auch wenn ich die while-Schleife ersetze durch


while(client.connected()) {
delay(10);
/* while(client.available()) {
Serial.write(client.read());
}*/
}

ändert sich das nicht.
(Serial ist ja stand-allone nicht mehr verfügbar!)

Moppi
21.10.2019, 10:51
Ich denke:

Du müsstest Dich entscheiden, ob die Connection zum Client bestehen bleibt oder geschlossen wird.

WiFiClient client = wifiserver.available();

Jetzt kannst Du mittels client mit dem Browser kommunizieren, der eine Verbindung hergestellt hat.
Die Verbindung sollte jetzt bestehen.

Da Du das jedesmal machst, wenn ein Datenaustausch mit dem Client statt gefunden hat, müsstest Du die Verbindung beenden, s. client.stop().

Der Client, also der Browser soll aber wohl wissen müssen, was passieren wird. Dazu sendest Du einen Header:



script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????



In diesem steht aber nicht, dass die Connection geschlossen werden soll.
Vielleicht mal mit einem korrekten Header anfangen:



script += ("HTTP/1.1 200 OK\r\n");
script += ("Content-Type: text/html\r\n");
script += ("Connection: close\r\n");
...





Von vorne:


Zuerst mit WiFiClient client = wifiserver.available(); ein Objekt holen, dass Kommunikation mit dem Browser erlaubt (Browser hat Connection hergestellt). Das kannst Du zur Not mit if(client)... überprüfen.

Dann prüfen, ob der Browser Daten gesendet hat und diese alle einlesen und verarbeiten.

Wenn fest steht, was er gesendet hat und die Daten (User und Passwort) richtig waren, dann die Seitendaten senden (inkl. dem Header wie oben).

Nach dem Datentransfer dem Browser mit delay(x) etwas Zeit geben, die Daten zu empfangen.

Dann, am Schluss, zum Schließen der Connection client.stop() verwenden.



MfG

HaWe
21.10.2019, 12:04
Ich denke:

Du müsstest Dich entscheiden, ob die Connection zum Client bestehen bleibt oder geschlossen wird.

WiFiClient client = wifiserver.available();

Jetzt kannst Du mittels client mit dem Browser kommunizieren, der eine Verbindung hergestellt hat.
Die Verbindung sollte jetzt bestehen.

Da Du das jedesmal machst, wenn ein Datenaustausch mit dem Client statt gefunden hat, müsstest Du die Verbindung beenden, s. client.stop().

Der Client, also der Browser soll aber wohl wissen müssen, was passieren wird. Dazu sendest Du einen Header:



script += ("HTTP/1.1 200 OK \n");
script += ("Content-Type: text/html \n");
script += ("\n"); // do not forget this one //????



In diesem steht aber nicht, dass die Connection geschlossen werden soll.
Vielleicht mal mit einem korrekten Header anfangen:



script += ("HTTP/1.1 200 OK\r\n");
script += ("Content-Type: text/html\r\n");
script += ("Connection: close\r\n");
...





Von vorne:


Zuerst mit WiFiClient client = wifiserver.available(); ein Objekt holen, dass Kommunikation mit dem Browser erlaubt (Browser hat Connection hergestellt). Das kannst Du zur Not mit if(client)... überprüfen.

Dann prüfen, ob der Browser Daten gesendet hat und diese alle einlesen und verarbeiten.

Wenn fest steht, was er gesendet hat und die Daten (User und Passwort) richtig waren, dann die Seitendaten senden (inkl. dem Header wie oben).

Nach dem Datentransfer dem Browser mit delay(x) etwas Zeit geben, die Daten zu empfangen.

Dann, am Schluss, zum Schließen der Connection client.stop() verwenden.



MfG

hi,
WiFiClient client = wifiserver.available();
habe ich ja schon ganz oben im Code stehen.

Ich habe nun die alten 3 Codezeilen durch die 3 neuen ersetzt, allerdings baut er jetzt gar keine website mehr auf - was habe ich übersehen? (ggf: wie lautet der komplette neue Code, falls nicht nur 1 Zeile betroffen ist?)

Moppi
21.10.2019, 12:41
ich habs mal etwas umgestellt - versuch das mal:




bool authorized=false;


void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();


if (client) {


//---------------------------------------
// debug
// authorized=true;


strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");





while ( client.connected() ) {
if (authorized) return;


if ( client.available() ) {
char c = client.read();


//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {
//client.flush();


//now output html data header


String script = "";


script += ("HTTP/1.1 200 OK\r\n");
script += ("Content-Type: text/html\r\n");
script += ("Connection: close\r\n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");


// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");


script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");


script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");


script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");


client.println(script);
delay(100);

//stopping client
client.stop();
//clearing string for next read
//readString = "";
}
}
//delay(1);
}
}
}

HaWe
21.10.2019, 13:03
leider springt er jetzt sofort wieder raus, wie ganz am Anfang,
und wenn ich einsetze vor client.stop();


//stopping client
while(client.connected()) {
delay(10);
}
client.stop();

dann baut er sie auf, beibt aber ewig drin hängen, auch nach korrektem login+pwd :(

Moppi
21.10.2019, 13:27
strupwd und struname werden doch überhaupt nicht aus dem gelesenen String readString extrahiert, aber anschließend verglichen und dann davon abhängig gemacht, ob authorized = true;

Das haut irgendwie hinten und vorne noch nicht hin.

HaWe
21.10.2019, 13:35
dieser Teil mit der Extrahierung von strupwd und struname ist hier nur verkürzt wiedergegeben, um die Lesbarkeit zu erhöhen, meine eigene Methode ist recht kompliziert.
Wie würdest DU diese Extrahierung samt Vergleich machen, und, wo wir gerade dabei sind, ggf. mit POST anstelle von GET?

Vieleicht liegt ja tatsächlich hier der Hase im Pfeffer...?

Moppi
21.10.2019, 13:39
ich habs nochmals geändert und ein Schnipsel eingefügt:



bool authorized=false;




void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();




if (client) {




//---------------------------------------
// debug
// authorized=true;




strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");









while ( client.connected() ) {
if (authorized) return;




if ( client.available() ) {
char c = client.read();




//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
while ( c != '\n') {
c = client.read();
}


if (c == '\n') {
//client.flush();




//now output html data header




String script = "";




script += ("HTTP/1.1 200 OK\r\n");
script += ("Content-Type: text/html\r\n");
script += ("Connection: close\r\n");
script += ("\n"); // do not forget this one //????
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");




// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");




script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");




script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");




script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");




client.println(script);
delay(100);

//stopping client
client.stop();
//clearing string for next read
//readString = "";
}
}
//delay(1);
}
}
}



entscheidend ist, dass die Seite jedesmal angezeigt wird, wenn der Browser eine Anfrage an den Server stellt. Denn erst dann kann man das Passwort eingeben und den Namen, was dann ausgewertet werden muss.
Ob das Passwort stimmt oder ob der Vergleich dazu hinhaut wissen wir nicht, weil der Teil fehlt. Man kann das umschreiben, ich habe aber nicht die Möglichkeit, das mit 2.5.x zu probieren - glaub ich.
Muss mal sehen. Das kann so schwer nicht sein.

HaWe
21.10.2019, 13:50
in dieser Form springt es wieder sofort aus der Website raus, wie ganz am Anfang.

- - - Aktualisiert - - -

mit


while(client.connected()) {
delay(10);
}

client.stop();

baut er wieder auf, bleibt aber auch wieder komplett im Formular hängen (wie zuvor)

Moppi
21.10.2019, 13:50
wie lese ich diese version beim nodemcu aus?

HaWe
21.10.2019, 13:56
Werkzeuge => Board => Boardverwalter =>....
dann in der Eingabezeile
nodeMCU
eingeben
dann steht die Version ganz oben im Feld, Version auswählen ganz unten

34420

34418

Moppi
21.10.2019, 14:17
habe 2.2.0, update wird geladen

jetzt 2.5.2

beim nächsten Programmupload auf das Board dann hoffentlich 2.5.2

Ceos
21.10.2019, 14:19
Ich bin mir zwar nicht sicher was du genau bezwecken willst, aber ich würde erstmal versuchen zu verstehen was ich für ein Verhalten erwarte, mich darüber schlau machen wie Browser sich in der gegebenen Situation verhalten und wie ich meinen Code bauen muss damit es auch mit jedem Browser überall funktioniert.

Webseiten darstellen ist kein Problem, man akzeptiert einen Client, ließt die Anfrage per client.read() aus, sucht die passende Webseite für die aufgerufene Adresse und gibt den HTML code zurück, flush, stop und fertig ist der Lack, das sollte auch einfach so ohne irgendwelche Probleme funktionieren.

Webaufrufe mit Daten vom Browser zum Server geht per GET oder POST, wobei man die GET Daten auch sofort übermitteln kann, sofern man weis was man eingeben muss.
Per POST braucht es erst ein Formular, welches man vorher auch zum Client senden muss, dafür braucht es also 2 Anfragen, die erste Anfrage welche die Webseite mit dem Formular an den client sendet und die 2te Anfrage als Action mit POST und dem ausgefüllten Formular.

Was du also schreiben musst ist eine Schleife, welche (sofern die Verbindung zum Browser offen hält mit wie Moppi schon beschrieben hatte, was allerdings auch nicht garantiert ist) immer client.read() benutzt um Anfragen zu empfangen, auszuwerten und zu verarbeiten und zu beantworten.

Zu jeder Anfrage muss es auch eine Webseite als Antwort geben, sonst beschwert sich dein Browser wie in deinem Fall dass der Server die Verbindung geschlossen hat!

Was du brauchst ist ein strukturierterer Ansatz für deine Aufgabe. Außerdem solltest du dich mit einfachen Session-Cookies beschäftigen, sonst bekomst du spätestens dann Probleme wenn du längere Zeit auf der Webseite bist, weil dein Browser irgendwann den Socket von sich aus schließt und du einen neuen "client" bekommst den du dann wieder neu authentifizieren musst. (oder du speicherst dir die IP des client als trick, aber das ist bei leibe nicht sicher und nur als workaround gemeint!!!!!!!)


--------------


Am besten schreibst du erstmal einen dummen Server, welcher Browseranfragen annimmt und an den Browser zurück spiegelt um erstmale in Gefühl für die Anfragen zu bekommen.

Wenn das klappt, braust du dir eine einfache Webseite zusammen, welche bei der richtigen Adresse auch ausgegeben wird.

Dann baust du in einer der Seiten einen Knopf für eine GET und einen Knopf + Formular für eine POST Anfrage ein.

Auf jeder Seite lässt du Platz um den Inhalt der Anfrage zu posten und auf Anfragen die du nicht lesen kannst Antwortest du dem Browser wie beim ersten Schritt mit der Anfrage als Antwort um zu verstehen was genau der Browser da gesendet hat.

So hangelst du dich dann bei deinem Adress-Parser langsam vorwärst und musst nicht in einem einzelnen Codeblock rumstricken

HaWe
21.10.2019, 14:34
naja, es funktioniert doch im Prinzip, bis auf einen "Schönheitsfehler", username wird korrekt geprüft und pwd auch - zumindest in der Version Seite 2 oben
https://www.roboternetz.de/community/threads/74132-esp8266-Arduino-IDE-neuer-Versuch-warum-wird-website-sofort-beendet?p=655516&viewfull=1#post655516 ,
und auch wenn man hier noch 2x hintereinander ENTER drücken muss.
Diesen Schönheitsfehler gilt es nun zufinden und ebenfalls auszumerzen - unter core 2.4.0 hat es ja auch noch 100%ig funktioniert.

Sehr schön wäre es auch, wenn man GET durch POST ersetzen könnte.

Cookies will ich keine setzen.

Deine sehr allgemeinen Tipps kann ich allerdings nicht umsetzen, mein Ursprungscode war bereits so leistungsfähig wie ich es überhaupt verstehen und schreiben konnte - für einen ganz neu geschriebenen Code wäre ich ntl auch sehr dankbar ;).

Ceos
21.10.2019, 14:40
Ich habe oben mal eine Empfehlung ergänzt wie du dich an deine konkrete Problematik heranarbeiten kannst.
Ich wollte eigentlich nur so höflich wie möglich darauf hinweisen dass man mit dem Code wie er ist nicht unbedingt weiterarbeiten sollte und nochmal sauber neu anfangen sollte weil amn sonst mit Phänomenen und Seiteneffekten arbeitet die nicht im geringsten Hilfreich für das Verständnis sind.

Ich schlage vor du schreibst einfach nochmal ein neues Beispiel welches nichts weiter macht als Anfragen entgegen zu nehmen und diese als HTML oder Text an den Browser zurück spiegelt.

Mit dem String den du da spiegelst kannst du dann einen Parser bauen um die Anfrage auszuwerten und entsprechend Webseiten auszugeben.

Wenn das klappt, kannst du dir dann eine POST und GET Anfrage in einer deiner Webseiten einbauen und spiegeln lassen um deinen Parser zu erweitern

edit: ich versuche hier nur mal einen kleinen Objektorientierten Ansatz für das Verständnis

Ich bin der Server und du der Browser, du kannst mich entweder mit der Zimmernummer und dem Geheimen Passwort ansprechen (GET mit Daten in der Aufrufzeile ... unsicher weil Klartext) und ich lasse dich rein
oder du musst erstmal mich fragen ob ich dir das Klemmbrett(Webseite) mit dem Login Formular gebe (GET) damit du es mir ausgefüllt zurück geben kannst (POST)

In jedem Fall muss ich wissen wer du bist und solange ich dich sehe (offener Socket) weis ich auch dass die Formulardaten oder Anfragen von dir sind. Wenn du allerdings nur einmal außer Sichtweite gehst muss ich annehmen dass du nicht mehr du bist oder du dich mir gegenüber ausweist.

HaWe
21.10.2019, 14:44
ich selber kann es nicht besser und ich würde es momentan auch nicht anders machen, so wie ich das Prinzip verstehe
- vlt hat Moppi ja mit seiner Version noch etwas mehr Erfolg, denn die letzte hängt ja auch wieder.
Wir hatten das Thema ja schon öfter - ich brauche keine allgemeinen Ratschläge, was ich brauche, sondern Code, der kompilierbar ist und den ich testen kann.
Konkrete Codevorschläge also immer gerne! 8)

Ceos
21.10.2019, 14:53
Das Problem ist, dass du noch nicht mal die Grundlage zu verstehen scheinst wenn man den Code ansieht. (nicht bös gemeint) Du verarbeitest nicht mal die Anfrage sondern wartest einfach auf "irgendeine" Anfrage und spuckst die Webseite aus.
Wenn du jemals authorized auf true setzt sollte der Browser theoretisch nie wieder antworten weil der client schon nach dem verbinden sofort mit einem return abgewürgt wird.

HaWe
21.10.2019, 14:56
wie gesagt, es funktioniert alles bis core 2.4.0, erst danch nicht mehr.
Sogar jetzt aber geht das Einloggen und Ausloggen (aus der Haupt-html-Seite) einwandfrei, denn dadurch wird authorized wieder auf false gesetzt.
Je nachdem,, wie authorized gesetzt ist, wird im Hauptprogramm (loop() ) entweder die Login Seite aufgerufen oder die Haupt-Website.

Wirklich hilfreich ist jetzt tatsächlich nur funktionierender Code für core 2.5.2

Ceos
21.10.2019, 14:58
Je nachdem,, wie authorized gesetzt ist, wird im Hauptprogramm (loop() ) entweder die Login Seite aufgerufen oder die Haupt-Website.

ah okay das war aus dem code auf seite 1 jetzt irgendwie nicht ersichtlich :D


Wirklich hilfreich ist jetzt tatsächlich nur funktionierender Code für core 2.5.2

dafür müsste ich erstmal arbeiten wenn du verstehst was ich meine :)

HaWe
21.10.2019, 14:58
tatsächlich lese ich aber auch die Eingabe aus und verarbeite sie (was ja auch funktioniert):


while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

readString.toCharArray(strinput, MAXLEN);
// hier fehlt ein kleiner Teil fürs Parsen:
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd


if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{...}

wenn du aber hier nicht am Code mit-arbeiten willst, dann herzlichen Dank bis hierhin... :)

Ceos
21.10.2019, 15:00
naja du versuchst das passwort und den usernamen zu finden aber du wertest nicht wirklich effektiv den aufruf aus und damit fehlt dir schonmal das grundlegende verständnis wie anfragen aussehen udn funktionieren

man kann nicht alles einfach so abkürzen oder muss sich einer library bedienen


wenn du aber hier nicht am Code mit-arbeiten willst, dann herzlichen Dank bis hierhin...

warum versuche ich dir gegenüber überhaupt noch freundlich zu sein wenn du einem immer die Tür ins Kreuz schlägst ... merkst du es eigentlich noch? Renn halt gegen deine selbst gemauerte Wand bis dir der Schädel platzt...

HaWe
21.10.2019, 15:08
s.o., ich habe dafür eigene Funktionen
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

ich brauche nun konkrete Codevorschläge...

ich warte mal, ob Moppi noch was einfällt.

Moppi
21.10.2019, 15:13
Ich habe mit der 2.5.2 auch Probleme. Opera zeigt den Seiteninhalt an, aber dafür hängt das nodeMCU. Firefox bringt die Meldung mit dem Reset, zeigt den Inhalt nicht an, dafür hängt das nodeMCU nicht.

Habe den Beispielcode von hier verwendet und etwas angepasst, damit bei mir der Login im WLAN funktioniert: https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/server-examples.html

Original funktioniert dieser Code gar nicht, weil der auf "\n" wartet und wo er es tut, kommt irgendwas durcheinander.


MfG

HaWe
21.10.2019, 15:18
bei mir haben alle Versionen seit 2.4.0 das geschilderte "Problem", irgendwie scheinen die eher für Fehler oder Ungenauigkeiten im Code anfällig zu sein - trotzdem müsste man es zum Laufen kriegen, sonst würden sie ja auch unter 2.4.0 nicht laufen.

- - - Aktualisiert - - -

PS,
hier übrigens meine Parserfunktionen, um username + pwd herauszufiltern:


//----------------------------------------------------------------------------
// String functions
//----------------------------------------------------------------------------

int16_t strstrpos(char * haystack, char * needle) // find 1st occurance of substr in str
{
char *p = strstr(haystack, needle);
if (p) return p - haystack;
return -1; // Not found = -1.
}

//-------------------------------------------------------
const int MAXLEN = 1024;
const int TOKLEN = 64;

//-------------------------------------------------------
char * cstringarg( char* haystack, char* vname, char* sarg ) {
int i=0, pos=-1;
unsigned char ch=0xff;
const char* kini = "&"; // start of varname: '&'
const char* kin2 = "?"; // start of varname: '?'
const char* kequ = "="; // end of varname, start of argument: '='
char needle[TOKLEN] = ""; // complete pattern: &varname=abc1234

strcpy(sarg,"");
strcpy(needle, kini);
strcat(needle, vname);
strcat(needle, kequ);
pos = strstrpos(haystack, needle);
if(pos==-1) {
needle[0]=kin2[0];
pos = strstrpos(haystack, needle);
if(pos==-1) return sarg;
}
pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ
while( (ch!='&')&&(ch!='\0') ) {
ch=haystack[pos+i];
if( (ch=='&')||(ch==';')||(ch==' ')||(ch=='\0') ||(ch=='\n')
||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
sarg[i]='\0';
return sarg;
}
if( (ch!='&') ) {
sarg[i]=ch;
i++;
}
}
return sarg;
}


// *SNIP*

cstringarg(strinput, "uname", struname); // uname
cstringarg(strinput, "upwd", strupwd); // upwd




sie funktionieren sehr gut, und sehr wschl liegt hier wirklich nicht das Problem - lasse mich aber gern vom Gegenteil überzeugen!

Moppi
21.10.2019, 15:28
Ja, schon. Bloß wenn Ivan Grokhotkov keinen lauffähigen Code hinbekommt ...

:)

Kannst Du bis auf die Grundfesten alles auseinandernehmen, das kann Wochen oder Monate dauern.

Probleme mit Datentypen, Steuerzeichen, Formaten ....

HaWe
21.10.2019, 15:32
Ja, schon. Bloß wenn Ivan Grokhotkov keinen lauffähigen Code hinbekommt ...

:)


...der ja auch nicht viel anders aussieht als unserer hier... :roll:

Moppi
21.10.2019, 15:39
Das Problem liegt in der Übertragung zum Browser oder am Inhalt selber. Kann nicht sein, dass ein Browser zwar den Inhalt anzeigt, aber das nodeMCU (vmtl. während der Kommuniaktion) hängen bleibt und ein anderer Browser den Inhalt gar nicht anzeigt und ihn also nicht interpretieren kann, dafür aber das nodeMCU nicht hängt.

Bei mir funktioniert es ab dieser Stelle z.B. gar nicht, mit keinem der beiden Browser:



// wait for end of client's request, that is marked with an empty line
if (line.length() == 1 && line[0] == '\n')

HaWe
21.10.2019, 15:43
immerhin funktioniert ja die Version auf S. 2
https://www.roboternetz.de/community/threads/74132-esp8266-Arduino-IDE-neuer-Versuch-warum-wird-website-sofort-beendet?p=655516&viewfull=1#post655516
schon ziemlich gut, danke noch mal
- vlt fällt ja jemand noch was ein wegen des 2x Enter- oder Button-drücken müssens... 8)

Moppi
21.10.2019, 15:50
letzteres passiert, wenn eine Eingabe verloren geht. Oder das Programm wartet auf Zeichen, kann die Übertragenen nicht zuordnen und verwirft sie - und erst beim nächsten Mal klappts wieder. Das kann auch dort passieren, wo Du das Passwort und den User extrahierst (bzw. die Zeichen dafür einliest).

HaWe
21.10.2019, 16:21
ja, ich denke da auch an das endofline-Zeichen \n vs. \r\n etc...
es geht aber nicht zufällig verloren, sondern immer das 1. Mal und immer nur das 1. Mal, und beim 2. Mal klappt es immer!

HaWe
22.10.2019, 08:51
@Moppi:
wie gehst du jetzt mit deinem Fehler bei der 2.5.2 um? gehst du wieder zurück auf 2.2.x oder 2.4.x oder versuchst du, es unter dem neuen Core zum Laufen zu kriegen?
(Es sind ja auch etliche Bug Fixes und neue Funktionen seit 2.5.x dazu gekommen sowie veränderte ältere Wifiserver und Websever Lbs im githiub repo https://github.com/espressif/arduino-esp32)

Moppi
22.10.2019, 09:57
Keine Ahnung, HaWe, ich brauchs momentan nicht und würde später nochmal ein Update ausführen.

Obwohl interessant wärs, wie sich der Code, den ich hatte, unter Version 2.4.x verhält.

Aber mit etwas Zeit würde ich noch etwas herumprobieren, Senden und Empfangen funktioniert vom Prinzip, das sieht nach einem Kommunikationsproblem aus. Hatte schon überlegt, genau zu schauen welche Bytes ankommen und auch selber Funktionen zu schreiben, um die zu verschicken, damit ich genau weiß, was da passiert.

Ich verwende nur die ESP8266WiFi.h

Mich würde jetzt interessieren, ob es bei Dir besser läuft jetzt. Das Problem mit dem doppelten Senden müsste man noch hinbekommen können, muss man suchen..



MfG

HaWe
22.10.2019, 10:26
Login wie gehabt 2x.
Ansonsten klappt die Kommunikation zu anderen esp8266 Web Clients einwandfrei, auch zu UDP Servern.
(Version wie auf S.2 oben (editierte Version)

Moppi
22.10.2019, 10:31
Das Beispielprogramm von Ivan funktioniert sehr gut. Unter Version 2.2.0. Nicht jedoch unter 2.5.2 - dort kommt es zu den Fehlern!

Lager doch mal Deine Routine, die Passwort und Username extrahier, in eine extra Funktion aus und binde die dann via Funktionsaufruf in dem Code ein, an dem wir gestern herumgespielt haben. Dann kann man gezielt suchen.



MfG

HaWe
22.10.2019, 10:35
ja, ähnlich wie bei mir vorher...

- - - Aktualisiert - - -

Probier doch auch mal 2.4.0, ich wette, da läuft auch der Ivan bei dir! 8)

Moppi
22.10.2019, 10:41
2.5.2 funktioniert nicht
2.4.2 funktioniert nicht
2.4.1 funktioniert nicht
2.4.0 funktioniert

HaWe
22.10.2019, 10:45
2.4.1 funktioniert auch nicht bei mir, nur bis 2.4.0

Moppi
22.10.2019, 10:48
über mehrere Versionen hinweg funktioniert es schon nicht mehr, dass das keinem auffällt?




String line = client.readStringUntil('\r');
Serial.print(line);
// wait for end of client's request, that is marked with an empty line
if (line.length() == 1 && line[0] == '\n')


könnte in diesem Zusammenhang an readStringUntil() liegen, bzw. dem, was darin verwendet wird und sich seit Version 2.4.0 geändert hat.

HaWe
22.10.2019, 12:14
doch, bei den issues gab es schon Meldungen, aber die neuen original-examples von esp klappten ja wieder weiterhin - nur für Code von anderen wie von Ivan oder von mir übernehmen die esp Leute keinen Support und verweisen aufs esp Forum. Ohne erkennbare Lösung, soweit ich es sehe.
Ich finde aber auch im esp32 repo keine original-esp-Codebeispiele für Eingabe von Strings per GET oder POST.

- - - Aktualisiert - - -

ich selber verwende ja nicht Ivans examples, aber nachdem du ja damit Erfahrung hast: melde doch mal deine Probleme mit 2.4.x ++ in Ivans issues!
hier ist ja deine/Ivans (?) repo bei github: https://github.com/esp8266/Arduino/blob/master/doc/esp8266wifi/server-examples.rst

Moppi
22.10.2019, 12:22
Wie es aussieht, gibt es (auch) ein Problem beim Senden der Daten an den Browser.

Opera stellt den Seiteninhalt dar, mach aber kein Refresh mehr. Da scheint beim Header was falsch zu sein, was am Browser ankommt (im Arduino-IDE-Quelltext ändert der sich ja nicht).
Firefox hat dann auch ein Problem und zeigt gar nichts an, wundert sich nur, dass die Connection beendet (reset) wird und bringt die Meldung (macht nat. dann auch kein Refresh der Seite).


Was ist denn "original-esp" ??? Welche LIBs gehören dazu und wo ist dazu die Doku??? - Dann benutzt man eben nur diese Sachen.

HaWe
22.10.2019, 12:27
ja, so etwas hast du ja oben schon gesschrieben.
Hast du die aktuelle Version des Codes verwendet?
https://github.com/esp8266/Arduino/blob/master/doc/esp8266wifi/server-examples.rst

Moppi
22.10.2019, 12:32
Hast du die aktuelle Version des Codes verwendet?
Sieht danach aus

HaWe
22.10.2019, 12:40
komplett so, unverändert?


#include <ESP8266WiFi.h>

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

WiFiServer server(80);


void setup()
{
Serial.begin(115200);
Serial.println();

Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");

server.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}


// prepare a web page to be send to a client (web browser)
String prepareHtmlPage()
{
String htmlPage =
String("HTTP/1.1 200 OK\r\n") +
"Content-Type: text/html\r\n" +
"Connection: close\r\n" + // the connection will be closed after completion of the response
"Refresh: 5\r\n" + // refresh the page automatically every 5 sec
"\r\n" +
"<!DOCTYPE HTML>" +
"<html>" +
"Analog input: " + String(analogRead(A0)) +
"</html>" +
"\r\n";
return htmlPage;
}


void loop()
{
WiFiClient client = server.available();
// wait for a client (web browser) to connect
if (client)
{
Serial.println("\n[Client connected]");
while (client.connected())
{
// read line by line what the client (web browser) is requesting
if (client.available())
{
String line = client.readStringUntil('\r');
Serial.print(line);
// wait for end of client's request, that is marked with an empty line
if (line.length() == 1 && line[0] == '\n')
{
client.println(prepareHtmlPage());
break;
}
}
}
delay(1); // give the web browser time to receive the data

// close the connection:
client.stop();
Serial.println("[Client disonnected]");
}
}

Moppi
22.10.2019, 13:00
oh, ich hab was gefunden. muss noch mit 2.5.2 überprüfen.

ok, alles klar so weit:

Ab Version 2.4.1 muss zwingend im Response-Header, im Arduino-IDE-Quelltext "Content-Length" angegeben werden, damit der Browser weiß, auf wieviele Zeichen er vom Server wartet.
Gut möglich, dass das vorher automatisch irgendwo hinzugefügt worden ist, aber ab Version 2.4.1 nicht mehr.

HaWe
22.10.2019, 13:03
Update:
ich habe den Code jtzt auf einem neuen esp8266 selber getestet, und tatsächlich tritt es auch bei mir so auf wie bei dir (Firefox):
2.2.0: läuft, website:
Analog input 2

2.5.2: sofortiger Abbruch,



Fehler: Verbindung unterbrochen

Die Verbindung zum Server wurde zurückgesetzt, während die Seite geladen wurde.

Die Website könnte vorübergehend nicht erreichbar sein, versuchen Sie es bitte später nochmals.
Wenn Sie auch keine andere Website aufrufen können, überprüfen Sie bitte die Netzwerk-/Internetverbindung.
Wenn Ihr Computer oder Netzwerk von einer Firewall oder einem Proxy geschützt wird, stellen Sie bitte sicher, dass Firefox auf das Internet zugreifen darf.


ich habe jetzt hier einen issue eröffnet: https://github.com/esp8266/Arduino/issues/6661

Moppi
22.10.2019, 13:13
nimm mal den Quelltext:



#include <ESP8266WiFi.h>
//#include <ESP8266WebServer.h>
//#include <FS.h> // muss vor <detail\RequestHandlersImpl.h> stehen
//#include <detail\RequestHandlersImpl.h>


String ssid = "...";
String password = "...";


//ESP8266WebServer webserver(80); // Webserver-Instanz f�r Port 80 erstellen
WiFiServer server(80);




void setup()
{
Serial.begin(115200);
Serial.println();


Serial.println("Connecting to " + ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid.c_str(), password.c_str());
WiFi.config(IPAddress(xxx,xxx,xxx,xx), IPAddress(xxx,xxx,xxx,xxx), IPAddress(xxx,xxx,xxx,xxx), IPAddress(xxx,xxx,xxx,xxx));

//WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println(" connected");


server.begin();
Serial.printf("Web server started, open %s in a web browser\n", WiFi.localIP().toString().c_str());
}




// prepare a web page to be send to a client (web browser)
String prepareHtmlPage()
{
String htmlPage =
String("HTTP/1.1 200 OK\r\n") +
"Content-Length: 44\r\n"+
"Content-Type: text/html\r\n" +
"Connection: close\r\n" + // the connection will be closed after completion of the response
"Refresh: 5\r\n" + // refresh the page automatically every 5 sec
"\r\n" +
"<!DOCTYPE html>" +
"<html>" +
"Analog input: " + String(analogRead(A0)) +
"</html>" +
"\r\n";
return htmlPage;
}


void loop()
{
WiFiClient client = server.available();
// wait for a client (web browser) to connect
if (client)
{
Serial.println("\n[Client connected]");
while (client.connected())
{
// read line by line what the client (web browser) is requesting
if (client.available())
{
String line = client.readStringUntil('\r');


Serial.print(line);
// wait for end of client's request, that is marked with an empty line
if (line.length() == 1 && line[0] == '\n')
{
client.println(prepareHtmlPage());
delay(100); // give the web browser time to receive the data
// close the connection:
client.stop();
Serial.println("[Client disonnected]");
break;
}
}
}
}
}

HaWe
22.10.2019, 13:23
ja, funktioniert jetzt mit 2.5.2 (habe WiFi.config() momentan auskommentiert)
was ist passiert?

Moppi
22.10.2019, 14:32
weiter oben lesen: https://www.roboternetz.de/community/threads/74132-esp8266-Arduino-IDE-neuer-Versuch-warum-wird-website-sofort-beendet?p=655595&viewfull=1#post655595

- - - Aktualisiert - - -

@hawe
habe Deinen ersten Quelltext, nach den neuen Erkenntnissen, nochmals modifiziert:



bool authorized=false;


void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();


//---------------------------------------
// debug
// authorized=true;


strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");


while ( client.connected() ) {
if (authorized) return;


if ( client.available() ) {
char c = client.read();


//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}


readString.toCharArray(strinput, MAXLEN);
// cstringarg(strinput, "uname", struname); // uname
// cstringarg(strinput, "upwd", strupwd); // upwd

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)
{
authorized = true;
readString = "";
return;
// return; // <<< selbes Ergebnis, egal ob kommentiert oder auskommentiert
}

//if HTTP request has ended
if (c == '\n') {
client.flush();


//now output html data header


String script="";
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");


// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");


script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");


script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");


script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");


//----------------------------------


String script1 = "";
script1 += ("HTTP/1.1 200 OK \n");
script1 += ("Content-Type: text/html \n");
script1 += ("Content-Length: ") + script.length() + ("\n");
script1 += ("\n"); // do not forget this one //????


script = script1+script;


client.print(script);
delay(100);


//stopping client
client.stop();
//clearing string for next read
//readString = "";
}
}
delay(1);
}
}

HaWe
22.10.2019, 15:18
KORREKTUR !!

update:

ich hatte noch das alte


while(client.connected()) {
delay(10);
}

vor dem client.close() mit drin, aber nun rausgelöscht....:


UND JETZT schaltet er korrekt nach dem 1. Enter/Button Click durch!

4x nachgetestet, nach Neustart und zwischen-Abort, immer ok!

Ich verneige mich - und werde es jetzt noch über ein paar Stunden weiter testen+beobachten!

Tausend Dank! 8)

Moppi
22.10.2019, 15:34
Hä?

Verstehe ich nicht. Wo hattest Du client.close() drinnen?
Wie sieht der Code jetzt aus, wo es funktioniert?


MfG

HaWe
22.10.2019, 15:46
äh, sorry, vor
// close the connection:
client.stop();

der "echte" ungekürzte Code ist dieser hier:





void handleNotAuthorized() {
String readString = "";
char strinput[MAXLEN], strupwd[TOKLEN], struname[TOKLEN] ;

WiFiClient client = wifiserver.available();

strcpy(strinput, "");
strcpy(strupwd, "");
strcpy(struname, "");


while ( client.connected() ) {
if (authorized) return;


if ( client.available() ) {
char c = client.read();


//read char by request
readString = "";
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}

if(strstr(website_upwd,strupwd)!=NULL & strstr(website_uname,struname)!=NULL)

readString.toCharArray(strinput, MAXLEN);
// cstringarg( char* haystack, char* vname, char* sarg )
// haystack pattern: &varname=1234abc, delimiters &, \n, \0, SPACE, EOF
cstringarg(strinput, "uname", struname); // uname
cstringarg(strinput, "upwd", strupwd); // upwd

// debug
Serial.print("strupwd >>>"); Serial.print(strupwd); Serial.println("<<<");
Serial.print("website_upwd>>>"); Serial.print(website_upwd); Serial.println("<<<");
Serial.print("readString>>>");Serial.println(readString);

if ( (strlen(strupwd)==strlen(website_upwd)) && (strcmp(website_upwd, strupwd)==0)
&& (strlen(struname)==strlen(website_uname)) && (strcmp(website_uname, struname)==0)
)
{
authorized = true;
readString = "";
return;
}

//if HTTP request has ended
if (c == '\n') {
client.flush();

//now output html data header
String script="";
script += ("<!DOCTYPE html> \n");
script += ("<html> \n");

script += ("<head> \n");

// utf-8 für "°" Zeichen
script += "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"> \n" ;
script += "<title>" ;
script += "</title> \n" ;
script += "</head> \n" ;
script += "<body> \n" ;

script += ("<h2><p style=\"color:rgb(255,0,191);\"> log in to proceed: </p> </h2> \n");

script += ("<FORM ACTION='/' method=GET > \n");
script += ("<h2>user name: <INPUT TYPE=text NAME='uname' VALUE='' MAXLENGTH='50'> </h2> \n");
script += ("<h2>password : <INPUT TYPE=PASSWORD NAME='upwd' VALUE='' MAXLENGTH='50'> </h2> \n");

script += ("<h2><INPUT TYPE=SUBMIT></h2> \n");

script += ("</FORM> \n");
script += ("<BR> \n");
script += ("</body> \n");
script += ("</html> \n");

//----------------------------------

String script1 = "";
script1 += "HTTP/1.1 200 OK \n";
script1 += "Content-Type: text/html \n";
script1 += "Content-Length: " + (String)script.length() + "\n";
script1 += "\n"; // do not forget this one //????

script = script1+script;

client.print(script);
delay(100);

//stopping client
/*
while(client.connected()) {
delay(10);
}
*/
client.stop();
}
}
delay(1);
}
}

Moppi
22.10.2019, 16:17
Warum so: (String)script.length()

bei mir funktionierte das auch ohne das "(String)"

???

PS: gib mal: "(String)" bei google ein, mit Gänsefüßchen oder ohne! :):)

HaWe
22.10.2019, 16:27
:p

bei mir ging es zunächst nicht, aber es stört jetzt auch nicht weiter ;)

Moppi
22.10.2019, 16:32
Soll das (String) extra in String konvertieren?

HaWe
22.10.2019, 16:35
ja, genau, habe es noch mal getestet und dann kommt ohne (String):


ESP8266_ServerHomeWebMail_078:1273:59: error: invalid operands of types 'const char*' and 'const char [2]' to binary 'operator+'

script1 += "Content-Length: " + script.length() + "\n";

was ja eigentlich verständlich ist, denn lenghth() ist ja eine Zahl, die man nicht an cstrings addieren kann.

Moppi
22.10.2019, 16:43
Ok. Gut! Danke! Hatte so etwas ähnliches im Hinterkopf. Nur es gibt Funktionen, wo man es nicht extra konvertieren muss. Hätte auch mit String(script.length(), DEZ) oder schlicht mit String(script.length()) funktioniert?

Jetzt können wir jedenfalls 2.5.2 weiter verwenden.

HaWe
22.10.2019, 16:58
ja, String(...) funktioniert auch als Funktion, (String) ist ein explizites typecasting.
Und ja, ich freue mich auch sehr, dass jetzt de 2.5.2 funktioniert!
Nochmals vielen Dank für die erfolgreiche Mitarbeit und Hilfe!

HaWe
23.10.2019, 19:38
PS,
ein Randproblem: wie lösen eigentlich Arduinorianer das Extrahieren des eingegeben Strings?
das ist zwar etwas, das ich gelöst habe mit eigenen Funktionen, aber ich kann mir ehrlich gessagt nicht vorstellen, dass es da bei Arduino noch keine fertige Funktion gibt...?



//----------------------------------------------------------------------------
// String functions
//----------------------------------------------------------------------------

int16_t strstrpos(char * haystack, char * needle) // find 1st occurance of substr in str
{
char *p = strstr(haystack, needle);
if (p) return p - haystack;
return -1; // Not found = -1.
}

//-------------------------------------------------------
const int MAXLEN = 1024;
const int TOKLEN = 64;

//-------------------------------------------------------
char * cstringarg( char* haystack, char* vname, char* sarg ) {
int i=0, pos=-1;
unsigned char ch=0xff;
const char* kini = "&"; // start of varname: '&'
const char* kin2 = "?"; // start of varname: '?'
const char* kequ = "="; // end of varname, start of argument: '='
char needle[TOKLEN] = ""; // complete pattern: &varname=abc1234

strcpy(sarg,"");
strcpy(needle, kini);
strcat(needle, vname);
strcat(needle, kequ);
pos = strstrpos(haystack, needle);
if(pos==-1) {
needle[0]=kin2[0];
pos = strstrpos(haystack, needle);
if(pos==-1) return sarg;
}
pos=pos+strlen(vname)+2; // start of value = kini+vname+kequ
while( (ch!='&')&&(ch!='\0') ) {
ch=haystack[pos+i];
if( (ch=='&')||(ch==';')||(ch==' \n')||(ch=='\r') ||(ch=='\0')
||(i+pos>=strlen(haystack))||(i>TOKLEN-1) ) {
sarg[i]='\0';
return sarg;
}
if( (ch!='&') ) {
sarg[i]=ch;
i++;
}
}
return sarg;
}


// *SNIP*

cstringarg(strinput, "uname", struname); // uname
cstringarg(strinput, "upwd", strupwd); // upwd
if ( (strlen(strupwd)==strlen(website_upwd)) && (strcmp(website_upwd, strupwd)==0)
&& (strlen(struname)==strlen(website_uname)) && (strcmp(website_uname, struname)==0)
)
{
//...
}

Moppi
23.10.2019, 20:59
Mit String-Funktionen.

Normalerweise geht das sinngemäß:

1. Liefere erstes Vorkommen eines Zeichens in Zeichenkette
2. extrahiere aus erster Zeichenkette eine Neue, von Position bis Position
3. suche in neuer Zeichenkette nach Zeichen, dass das Ende markiert
4. extrahiere vom Anfang der Zeichenkette bis zu der Position des Endezeichens
5. gewünschter Inhalt ist extrahiert

Zwei Methoden für Strings habe ich für Arduino schon gefunden:

- indexOf()
- lastIndexOf()

interessant auch:
- substring()

indexOf() findet die Position eines gesuchten Zeichens
substring() extrahiert eine Zeichenkette anhand einer Start- und Endposition


Arduino.cc, TUTORIALS (https://www.arduino.cc/en/Tutorial/HomePage)> Built-In Examples (https://www.arduino.cc/en/Tutorial/BuiltInExamples)> 08.Strings

HaWe
23.10.2019, 21:05
ja, so schrittweise habe ich es ja prinzipiell auch gemacht in meinen Funktionen, ich meinte aber fertige Arduino-Funktionen, die prinzipiell alles komplett erledigen ( allerdings bei mir mit ISO C ctrings, nicht C++ Strings)

Moppi
23.10.2019, 21:08
Musst Du eine Funktion schreiben, dies das dann erledigt, wie Du das brauchst. Oder vielleicht gibt es eine fertige Bibliothek schon?
Braucht man aber auch nicht wirklich. Wenn man die Zeichenkette kennt, die kommt, also weiß, wo Start- und Endzeichen sind, kann man so einen Ausdruck in einer Codezeile formulieren.

MfG

Moppi
24.10.2019, 06:17
zum Beispiel:

Wenn der String so vom Browser, per GET, übermittelt wird:


?uname=...&upwd=...


Dann kann die ganze Zeile eingelesen werden mit:


String rS = client.readStringUntil('\r');

Und das Extrahieren der Informationen in der richtigen Reihenfolge, wenn nur zwei Felder existieren, könnte dann so funktionieren:



String website_uname = rS.substring(rS.indexOf('=')+1,rS.indexOf('&'));
String website_upwd = rS.substring(rS.lastIndexOf('=')+1);

Sollen die Feldbezeichnungen überprüft werden, stehen die Feldbezeichnungen und deren inhalte (upwd=...) in anderer Reihenfolge, soll die Funktion Inhalte, beliebig übermittelter Formularfelder, extrahieren? - Dann wird das Vorgehen natürlich komplizierter.


MfG


PS: der Code ist nur beispielhaft, habe nicht verifiziert, ob er so fehlerfrei compiliert wird. Soll nur der Anschauung dienen, wie es gemeint ist.

HaWe
24.10.2019, 08:09
nein, es ging doch nicht darum, so eine Funktion aus Einzel-Schritten neu zu schreiben, genau das habe ich doch bereits getan (cstringarg() ).
Es ging darum, ob Arduino so etwas wie mein cstringarg() bereits fertig für diese und ähnliche Zwecke zur Verfügung stellt, das würde es für komplette Anfänger einfacher machen und es müsste nicht jeder das Rad neu erfinden.

Moppi
24.10.2019, 09:35
Ich hatte Dich schon richtig verstanden, ich kenne doch Deinen Quellcode mit dem cstringarg() wo wir lange dran gebastelt haben, weil da auch was im argen war. Da kamen auch noch in andern Foren Fragen dazu auf.
Anfänger und Arduino-"Bordmittel", da würde ich schon so etwas hernehmen: rS.substring(rS.indexOf('=')+1,rS.indexOf('&'));
Ist auch für Anfänger einfach zu verstehen, ist ja nichts besonderes dran. Das Rad ist ja damit schon erfunden. Das sind gängige Lösungen, die Du überall antriffst (C++,Java,JavaScript ..).

Man muss noch was anderes bedenken:

Für so kleine Aufgaben lohnt es nicht, viel Overhead dazu zu packen, was den Gesamtquellcode und das fertige Kompilat unnötig aufblähen würde. Solche Universalmethoden (bei Objekten) belegen eine Menge Platz, nur, damit es einen kleinen Tacken bequemer ist. Damit belegst Du dann ein Vielfaches an Speicherplatz mehr, mal von der Rechenzeit / Taktzyklen abgesehen. Für seine eigenen Zwecke kann man das in eine Funktion packen, um das nicht immer neu schreiben zu müssen. Allerdings ist der Funktionsaufruf, in Gänze, dann vermutlich kaum kürzer.




MfG

HaWe
24.10.2019, 10:26
mit cstringarg() lag nichts "m Argen", das funktionierte von Anfang an bis jetzt einwandfrei, und es kann ja vielfache verschiedene Variablen über ihre verschiedenen Namen und samt ihrer verschiedenen Werte aus sehr langen zusammengesetzten cstrings herausextrahieren. Bei meinem Ursprungscode war prinzipiell der einzige Knackpunkt, dass zusätzlich eine Längenübermittlung beim Lesen und senden eines hthml-Inputstrings nötig ist.

Man braucht so etwas wie cstringarg() allerdings ständig, auch z.B. wenn man z.B. zwischen esp-Master und mehreren esp clients Variablenwerte hin und her schicken will.

Aber ich verstehe deine Antwort dann also richtig als "nein, du kennst auch noch keine komplette, fertige Funktion dafür in einer existierenden Arduino-Lib"... 8)

Moppi
24.10.2019, 11:22
Nein, ich kenne keine fertigen Bibliotheken, weil ich bis jetzt keine brauchte, sie also auch nie gesucht habe.
Da Du aber nach Arduino-Funktionen fragtest, kann man wohl nur die String-Methoden nennen, die ermöglichen Strings zu durchsuchen und Teile daraus zu extrahieren.


MfG

HaWe
24.10.2019, 11:25
nein, denn es ging ja in meiner Frage um eine fertige Funktion, die alles mit Suchen und Extrahieren komplett macht.

Moppi
24.10.2019, 12:26
Und jetzt? Was soll daraus werden? Wie es soll es weiter gehen?


MfG

Ceos
24.10.2019, 12:31
https://github.com/nodejs/http-parser

so etwas in der Art?
Und statt

recved = recv(fd, buf, len, 0);

macht du halt deine client.read() Schleife und befüllst den "buf" selbst

edit: die examples sind allesamt gruselig (malloc und co.) ... aber anpassbar

HaWe
24.10.2019, 13:20
ich habe den Parser jetzt noch nicht getestet, aber auf den 1. Blick könnte er machen was er soll.
Arduinorianer müssten dann allerdings diese Lib in ihren Code einbinden, was aber vermutlich auch nicht (viel) einfacher ist als mein cstringarg(). Ich dachte, dass eine integrierte Arduino-Funktion dafür zur Verfügung stehen könnte, in einer Arduino-Standardbibliothek. Scheint es aber tatsächlich nicht zu geben.
Mal gucken, ich verwende dann selber meine cstringarg() weiter, vielleicht wird mal eine Lib mit noch mehr Funktionen draus und die kann ich dann ja Arduino für den Library-Manager zum Upload/Download anbieten.

Ceos
24.10.2019, 13:29
dass eine integrierte Arduino-Funktion dafür zur Verfügung stehen könnte

der Wifiserver und der WifiESPServer und der ESP8266Server scheinen da wohl eine art Unterstützung zu haben, aber das waren sehr diffuse Diskussionen in englisch bei denen es nicht exakt um dein Problem ging, daher kann ichd a auch nichts genaueres dazu sagen, aber es hat mich auch stark gewundert dass man mit µPython-Flask so umfangreiche Unterstützung bekommt aber der Arduino WifiServer so spärlich bestückt ist

HaWe
24.10.2019, 13:38
ja, das kenne ich auch teilweise. Die Libs für esp (Wifi- und Web-Server etc.) stammen aber von esp, nicht von Arduino, und die esp-devs sind da eh sehr komisch drauf. ;)

Ceos
24.10.2019, 13:40
da eh sehr komisch drauf

ich würde eher sagen sie denken weiter, gerade WEIL arduino an manchen Stellen echt Schwächen hat, aber die Umsetzung ist definitiv "individuell"

edit: noch ein anderer Ansatz als Idee ohne irgendwas probiert oder gesucht zu haben ... wie wäre es mit regular expressions?! ich denke dafür müsste arduino definitv eine Unterstützung aufweisen, aber regular Expressions sind für sich schon wieder ein neues Arbeitsthema (ich komm jendefalls nciht so wirklich klar damit), bietet aber extrem flexible Scan-Möglichkeiten ohne mit Stringutils rum zu machen. Und man kann es auch bequem simulieren

Einfach den Request ausgeben lassen und kopieren, bei https://regex101.com/ z.B. eingeben und den regulären Ausdruck solange tunen bis er das richtige ausspuckt :)

Moppi
24.10.2019, 18:42
Es gibt eine Bibliothek für Arduino: https://playground.arduino.cc/Code/TextFinder/



MfG

Ceos
25.10.2019, 07:06
Das sieht doch mal nach RegEx-Lite aus :D nette Library!

Moppi
26.10.2019, 12:27
der Wifiserver und der WifiESPServer und der ESP8266Server scheinen da wohl eine art Unterstützung zu haben, aber das waren sehr diffuse Diskussionen in englisch bei denen es nicht exakt um dein Problem ging, daher kann ichd a auch nichts genaueres dazu sagen, aber es hat mich auch stark gewundert dass man mit µPython-Flask so umfangreiche Unterstützung bekommt aber der Arduino WifiServer so spärlich bestückt ist

Die ESP8266WebServer-Klasse stellt bessere Methoden zur Verfügung, mit denen sich viele dieser Sachen erledigen lassen, wie Daten aus dem Header auslesen etc.. So weit ich - kurz überflogen - gesehen habe, ist dort einiges enthalten, um das Handling mit Webseiten zu vereinfachen.


MfG

HaWe
26.10.2019, 14:40
Die ESP8266WebServer-Klasse stellt bessere Methoden zur Verfügung, mit denen sich viele dieser Sachen erledigen lassen, wie Daten aus dem Header auslesen etc.. So weit ich - kurz überflogen - gesehen habe, ist dort einiges enthalten, um das Handling mit Webseiten zu vereinfachen.


MfG

aber nichts, was meinem cstringarg() entspricht, für Anwendungen wie bei dem TOP Beispiel.

Moppi
26.10.2019, 14:54
.args(): liefert Zahl der Parameter, im Query-String
.argName(x): liefert den Namen des Arguments x, vom Query-String
.arg(x): liefert den Parameter, des Arguments x, vom Query-String

.arg(String name): liefert den Wert des Parameters name

MfG

HaWe
26.10.2019, 15:50
in welcher lib für welche Klasse?

Moppi
26.10.2019, 16:03
Verstehe ich nicht. https://www.roboternetz.de/community/threads/74132-esp8266-Arduino-IDE-neuer-Versuch-warum-wird-website-sofort-beendet?p=655726&viewfull=1#post655726

HaWe
26.10.2019, 18:54
Verstehe ich nicht. https://www.roboternetz.de/community/threads/74132-esp8266-Arduino-IDE-neuer-Versuch-warum-wird-website-sofort-beendet?p=655726&viewfull=1#post655726
du gibst nur Methoden an,

.args(): liefert Zahl der Parameter, im Query-String
.argName(x): liefert den Namen des Arguments x, vom Query-String
.arg(x): liefert den Parameter, des Arguments x, vom Query-String
.arg(String name): liefert den Wert des Parameters name

die sind aber gekapselt in Klassen.
Es sind z.B. keine Methoden der String-Klasse und auch keine Methoden der WiFiClient -Klasse.
Also wie heißt die Klasse dazu?


oder, anders gefragt:
wie willst du diese Funktionen nutzen, wenn du einen String erhalten hast über


WiFiClient client = wifiserver.available();
...
while ( (readString.length() < TOKLEN) && (c != '\n') ) {
readString += c;
c = client.read();
}



ich verrate dir dazu so viel: Dies alles funktioniert nicht:


client.args(): liefert Zahl der Parameter, im Query-String
client.argName(x): liefert den Namen des Arguments x, vom Query-String
client.arg(x): liefert den Parameter, des Arguments x, vom Query-String
client.arg(String name): liefert den Wert des Parameters name

// und ebensowenig:
readString.args(): liefert Zahl der Parameter, im Query-String
readString.argName(x): liefert den Namen des Arguments x, vom Query-String
readString.arg(x): liefert den Parameter, des Arguments x, vom Query-String
readString.arg(String name): liefert den Wert des Parameters name




Generating function prototypes...
error: 'class WiFiClient' has no member named 'args'
...
exit status 1
'class WiFiClient' has no member named 'args'


denn vermutlich sind es Methoden der esp8266 webserver-Klasse (IIRC), die du gefunden hast, und das nützt uns hier in der WifiClient-Klasse oder der String-Klasse nichts.

Also kannst du damit keinen String weiter verarbeiten, den ein WiFiClient erhalten hat, sondern nur einen, den ein esp8266 webserver erhalten hat
- genau deswegen habe ich nämlich cstringarg() geschrieben 8)

PS: ich habe diese esp8266 webserver-Methoden bei den esp-Leuten auch schon vor langer Zeit als Verbesserung für die webclient-Klasse als Erweiterung vorgeschlagen, aber sie haben es als nicht unterstützenswert abgelehnt.
Genau das meint ich übrigens u.a. auch als ich schrieb: "komisch drauf".

Ceos
26.10.2019, 19:05
DAs ist einer der GRünde warum ich mit den Methoden von den unterschiedlichen Libs eigentlich garnicht erst anfange wollte, wir werden hier zu Hardwarespezifisch und das sind alles irgendwie nur "proprietäre" Lösungen

ICh bin auch nciht schlau geworden in welchem Modul aus welcher Version nur welche Implementation steckt, daher hatte ich auch einne externe Lib vorgeschlagen, auch wenn man die erst wieder einbinden muss, scheint sie zumindest gereift und stabil von dem was ich im Bugtracker lese

HaWe
26.10.2019, 20:06
der Grund ist eigentlich eher, dass die esp Entwickler manche Methoden in manchen Klassen implementiert haben und in anderen nicht.
Das hat nichts mit hardwarespezifisch zu tun, denn ALLES ist ja für ESP8266, nur einmal für die Kommunikation mit anderen esp (.args enthalten), und das andere mal für die Kommunikation mit selber aufgebauten html-websites (.args NICHT enthalten).
Ähnliches gilt für den TextFinder, der nur *streams akzeptiert, aber keine Strings und keine cstrings.

Meine cstringarg() Funktion samt ststrpos() ist ja nun quasi eine Funktion einer externen lib, nur ist sie offenbar in dieser Kürze und Würze noch nicht für Arduino-user allgemein verfügbar. 8)

Damit können wir dann aber auch dieses Thema schließen, denke ich.

Moppi
26.10.2019, 21:05
Hallo,

ich wollte mich nicht wiederholen, was auch unnötig war, aber mach ich es - zu Lasten des Servers, auf dem das Forum sein Dasein fristet - eben nochmal:

Zitat von Ceos

der Wifiserver und der WifiESPServer und der ESP8266Server scheinen da wohl eine art Unterstützung zu haben, aber das waren sehr diffuse Diskussionen in englisch bei denen es nicht exakt um dein Problem ging, daher kann ichd a auch nichts genaueres dazu sagen, aber es hat mich auch stark gewundert dass man mit µPython-Flask so umfangreiche Unterstützung bekommt aber der Arduino WifiServer so spärlich bestückt ist







Darauf schrieb ich:


Die ESP8266WebServer-Klasse stellt bessere Methoden zur Verfügung, mit denen sich viele dieser Sachen erledigen lassen, wie Daten aus dem Header auslesen etc.. So weit ich - kurz überflogen - gesehen habe, ist dort einiges enthalten, um das Handling mit Webseiten zu vereinfachen.

Nach einem kurzen Einwand HaWe's schrieb ich dann:


.args(): liefert Zahl der Parameter, im Query-String
.argName(x): liefert den Namen des Arguments x, vom Query-String
.arg(x): liefert den Parameter, des Arguments x, vom Query-String

.arg(String name): liefert den Wert des Parameters name




Wir führen doch eine Diskussion(?). Mit "verstehe ich nicht" meinerseits war gemeint, dass ich nicht verstehe, warum man sich nicht erinnern kann, was zwei/drei Sätze vorher gesagt / geschrieben wurde; es könnte auch nachgelesen werden; obwohl ich es nochmals verlinkt habe, wo die Antwort zu finden ist, wird es trotzdem nicht gelesen. - Macht nichts!



Bin auch nur drauf gestoßen, weil ich mich gerade mal etwas näher damit befasse.



MfG

- - - Aktualisiert - - -

Bevor es jetzt noch absurder wird, bin ich mal raus aus dem Thread.

HaWe
26.10.2019, 22:11
ach so, das mit den "besseren Funktionen" war nur ganz allgemein auf andere esp Libs bezogen - das hatte ich nicht verstanden.
Ja, das stimmt.
Ich dachte, es war gemeint in Bezug auf den WiFiClient Code aus dem TOP, quasi als Lösung, um dessen Funktionen zu ersetzen
- aber darauf kann man seine Methoden ja nicht anwenden, und daher meine Antwort, dass es nicht ginge
- aber das war ja dann auch genau das, was du ebenfalls meintest.