Hallo,
ich möchte mit einem ATmega168 und dem ENC28J60 Lanmodul Daten über
TCP/HTTP an einen Webserver (im lokalen Netz) senden und die Antwort
(wenige Bytes) auslesen.
Verwendet wird der TCP/IP-Stack von tuxgraphics.org (Version 5.10). Das
Senden des GET-Befehls funktioniert, die Anfrage wird vom Server
beantwortet und der Statuscode wird vom Stack richtig ausgelesen,
allerdings scheint es keine Möglichkeit zu geben, um den Inhalt
auszulesen.
Die Funktion zum Auslesen des Statuscodes:
uint16_tweb_statuscode=0;// tcp status is OK but we need to check http layer too
3
uint8_ti=0;
4
if(fd!=www_fd){
5
(*client_browser_callback)(500,0,0);
6
return(0);
7
}
8
if(statuscode==0&&len_of_data>12){
9
// we might have a http status code
10
// http status codes are 3digit numbers as ascii text. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
11
// The buffer would look like this: HTTP/1.1 200 OK\r\n
12
// web_statuscode=0 means we got a corrupted answer
13
if(client_browser_callback){
14
if(isblank(bufptr[datapos+8])&&isdigit(bufptr[datapos+9])&&isdigit(bufptr[datapos+11])){// e.g 200 OK, a status code has 3 digits from datapos+9 to datapos+11, copy over the web/http status code to web_statuscode:
Benötigt wird nur der letzte Absatz, hier also "19:04:05". (Nein, ich
möchte NICHT die Uhrzeit übertragen, sondern "richtige" Daten. Momentan
dient die Uhrzeit nur als Platzhalter zum Testen.)
Die Länge der Daten wird nicht konstant sein.
Wie komme ich jetzt an diese Daten?
Die ganze Datei ip_arp_udp_tcp.c ist angehängt. Aufgerufen wird
client_browse_url(...)
Danke für eure Hilfe!
Der HTTP-Header wird mit einer Leerzeile, also zwei Zeilenumbrüchen,
beendet. Danach folgen bei HTTP/1.0 ohne Keepalive die Daten, bis die
Verbindung abbricht.
Für HTTP/1.1 solltest du unbedingt den "Content-Length"-Header
auswerten, denn da steht drin, wieviele Daten (in Bytes) du bekommst.
Du musst also nur nach "\r\n\r\n" suchen ("\n\n" ist nicht
standardkonform, kommt aber manchmal auch vor) und findest direkt
dahinter deine Daten.
Eventuell findest du die Daten auch einfach bei
bufptr[datapos] bis bufptr[datapos+len_of_data]. Möglicherweise sind die
Daten an der Stelle noch nicht vollständig (weil die Anfrage in mehreren
TCP-Paketen ankam).
Danke für die Antwort!
Da die übertragenen Daten immer im Format {Daten...} sind, müsste es
genügen, nur nach '{' bzw. '}' zu suchen und den Bereich dazwischen in
ein Array zu kopieren.
So ist es mir auch mit folgendem Code gelungen, die Position von '{' zu
finden:
1
uint8_t a=datapos;
2
while(bufptr[a] != '{')
3
{
4
a++;
5
}
Jetzt sollte man eigentlich, von a ausgehend, auch '}' finden können:
1
uint8_t b=a;
2
while(bufptr[b] != '}'){
3
b++;
4
}
Mit diesem Code steckt der AVR in einer Endlosschleife fest, obwohl '}'
nur wenige Bytes von a entfernt ist.
S. R. schrieb:> Möglicherweise sind die> Daten an der Stelle noch nicht vollständig (weil die Anfrage in mehreren> TCP-Paketen ankam).
Das ist hier nicht der Fall. Alles kommt in einem Paket an und befindet
sich auch im bufptr-Array.
Wenn ich alles von a bis a+50 ausgebe, erhalte ich auch alle Daten
einschließlich der abschließenden '}'.
Da die Daten aber keine feste Länge haben, möchte ich gern die erste
Version verwenden.
Die sollte eigentlich problemlos funktionieren. Aus irgendeinem Grund
tut sie das aber nicht, sondern bleibt in der Schleife stecken.
Irgendjemand eine Idee?
Hans Peter schrieb:> Da die übertragenen Daten immer im Format {Daten...} sind, müsste es> genügen, nur nach '{' bzw. '}' zu suchen und den Bereich dazwischen in> ein Array zu kopieren.
Das hattest du nicht erwähnt, und es ist auch kein sinnvoller Ansatz.
Nach HTTP-Protokoll folgen die Daten nach der feststehenden Zeichenkette
"\r\n\r\n" und gehen bis zu der Länge, die im Content-Length-Header
angegeben wurde oder bis zum Verbindungsende.
Alles andere ist hingepfuscht und wird dir irgendwann mal Schmerzen
bereiten, bevorzugt in dem Augenblick, wo du für eine Reparatur
wirklich keine Zeit hast.
> Mit diesem Code steckt der AVR in einer Endlosschleife fest, obwohl '}'> nur wenige Bytes von a entfernt ist.
Wie groß sind deine Daten, inklusive HTTP-Header?
Wie groß ist die größte Zahl, die du in einem int8_t speichern kannst?
> Alles kommt in einem Paket an und befindet> sich auch im bufptr-Array.
Kannst du das garantieren oder ist das nur zufällig in deinen Tests der
Fall? Was passiert, wenn du aus Spaß mal eine MTU von 256 einstellst?
S. R. schrieb:> Wie groß sind deine Daten, inklusive HTTP-Header?> Wie groß ist die größte Zahl, die du in einem int8_t speichern kannst?
Tatsächlich, die 8 Bit des uint8_t reichen gerade noch für den Header
ohne Daten aus. Mit uint16_t funktioniert alles einwandfrei.