Forum: Mikrocontroller und Digitale Elektronik Serial-to-Ethernet: Welche Daten für URL senden?


von Matthias (Gast)


Lesenswert?

Hi,

ich habe ein Serial-to-Ethernet-Wandler, mit dem ich einen URL senden 
möchte. Ich habe mal mit Wireshark geschaut, was bei dem URL-Senden vom 
Browser gesendet wird. Diese Daten (Header und Anforderungs-String) habe 
ich dann im Quelltext kopiert und nacheinander auf dem UART gesendet:
1
char caHeader[] = {
2
0x00, 0x20, 0x4a, 0x97, 0x6a, 0xb0, 0x94, 0xc6,
3
0x91, 0x51, 0x98, 0xbd, 0x08, 0x00, 0x45, 0x00,
4
0x01, 0xf3, 0xbe, 0xe9, 0x40, 0x00, 0x80, 0x06,
5
0x00, 0x00, 0xc0, 0xa8, 0xb2, 0x27, 0xc0, 0xa8,
6
0xb2, 0x35, 0xf8, 0x00, 0x00, 0x50, 0x4a, 0xcc,
7
0x78, 0xeb, 0x07, 0x01, 0x54, 0xa1, 0x50, 0x18,
8
0xfa, 0xf0, 0xe7, 0x93, 0x00, 0x00}; 
9
10
strcpy(caString, "GET / HTTP/1.1\r\n");
11
strcat(caString, "Host: 192.168.178.53\r\n");
12
strcat(caString, "Connection: keep-alive\r\n");
13
strcat(caString, "Upgrade-Insecure-Requests: 1\r\n");
14
strcat(caString, "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36\r\n");
15
strcat(caString, "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9\r\n");
16
strcat(caString, "Accept-Encoding: gzip, deflate\r\n");
17
strcat(caString, "Accept-Language: de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7\r\n");

Aber die angesprochene IP-Adresse reagiert nicht. Im Wireshark sehe ich 
kurioserweise auch nicht die Anforderung des URL, die ich gesendet habe. 
Auf dem UART gehen aber die Daten raus. Ist im Quellcode etwas 
unvollständig oder falsch?

Die Infos im Header sind mir nicht verständlich, was für eine genaue 
Bedeutung haben die?

von Martin R. (mme)


Lesenswert?

Du willst das Gerät mit der IP-Adresse 192.168.178.53 damit ansprechen?

von Dergute W. (derguteweka)


Lesenswert?

Moin,

Matthias schrieb:
> Die Infos im Header sind mir nicht verständlich, was für eine genaue
> Bedeutung haben die?
Wenn du den caHeader meinst, die kannst du evtl. damit aufschluesseln:

https://en.wikipedia.org/wiki/Ethernet_frame

Insbesondere das Bild:
https://en.wikipedia.org/wiki/File:Ethernet_Type_II_Frame_format.svg

Gruss
WK

von Jim M. (turboj)


Lesenswert?

Matthias schrieb:
> ich habe ein Serial-to-Ethernet-Wandler, mit dem ich einen URL senden
> möchte.

Welchen genau? Viele Wandler haben ein Manual wo man genau nachlesen 
kann wie sie angesprochen werden möchten.

Den Ethernet Header sendet man normalerweise nicht mit, muss dafür aber 
irgendwie die Zieladresse angeben. Normalerweise läuft auf dem UART ein 
Protokoll.

von Matthias (Gast)


Lesenswert?

Ja, ich möchte die IP-Adresse 192.168.178.53 damit ansprechen.

Ich habe einen Lantronix X-Port Artikel-Nr.: XP1002000-05R). Der ist so 
konfiguriert, daß eigentlich alles 1:1 rein und raus geben sollte. Das 
Senden einer Test-HTML-Seite geht damit, aber die URL-Anforderung geht 
nicht raus.

von foobar (Gast)


Lesenswert?

Ich habe mal kurz das Users-Guide durchgeblättert und wenn ich das 
richtig sehe, geht das höchstens über die Modem-Emulation mit entspr 
AT-Kommandos(ATDT zum Verbindungsaufbau, etc) - erst danach kannst du 
die HTTP-Kommunikation durchführen (+++ATH zum Verbindungsabbruch).

von foobar (Gast)


Lesenswert?

> höchstens über die Modem-Emulation

Scheint, dasses noch eine andere Methode gibt - schau mal unter "Manual 
Connection" (S. 52ff); könnte sein, dass das deinen "caHeader" erklärt.

von Martin R. (mme)


Lesenswert?

Beitrag "HTTP Request (Wie kann ich es machen?)"

Da hat schon mal jemand eine ähnliche Frage gehabt. Nämlich den XPort 
als Seriell<->TCP Brücke verwendet und will einen GET-Request senden. 
Aber leider steht dort nicht, ob es am Ende geklappt hat.

von Stefan F. (Gast)


Lesenswert?

Nach dem letzten Header musst du eine leere Zeile "\r\n" senden.

Ich würde dir empfehlen, das HTTP/1.0 Protokoll zu benutzen, denn 
ansonsten kann es dir passieren, dass der Server die Antwort in Chunks 
zerlegt, die du decodieren und zusammenfügen musst.

> Accept-Encoding: gzip, deflate

Das willst du mit wahrscheinlich nicht, oder kann dein Programm 
komprimierte Streams dekomprimieren?

Schau dir Kapitel 10 in 
http://stefanfrings.de/mikrocontroller_buch/Einstieg%20in%20die%20Elektronik%20mit%20Mikrocontrollern%20-%20Band%202.pdf 
an, da wird das HTTP 1.0 Protokoll so weit erklärt, wie man für 
Mikrocontroller-Anwendungen typischerweise braucht.

von Martin R. (mme)


Lesenswert?

Habe was interessantes gefunden: 
https://www.tigoe.com/pcomp/code/PHP/25/#more-25
Das scheint mit einem XPORT funktioniert zu haben.

von Matthias (Gast)


Lesenswert?

Ich habe nun etliches den ganzen Tag ausprobiert und mich versucht 
einzulesen in das Thema. Aber ich muß ehrlich gestehen, daß ich total 
verwirrt bin. Ich habe gedacht, wenn ich das selbe sende wie der Browser 
beim GET, dann wird der Server schon antworten. So einfach ist es leider 
nicht.

Ich denke das mit dem GET und Host wird schon richtig sein, aber da muß 
doch sicherlich noch etwas vorher gesendet werden. Mir ist aber nicht 
ganz klar, was.
1
void http_Request(void)
2
{
3
unsigned int uiAnzahlBytes;
4
5
strcpy(caString, "GET /login.htm HTTP/1.1\r\n");
6
strcat(caString, "Host: 192.168.178.53\n\n");  // server
7
uiAnzahlBytes = strlen(caString);
8
HAL_UART_Transmit_IT(&huart2, caString, uiAnzahlBytes);
9
}



Auf der Seite https://www.tigoe.com/pcomp/code/PHP/25/#more-25 hat mich 
verwirrt, daß er erst mal einen Server mit dem XPort connected hat:
1
void xportConnect() {
2
  //   send out the server address and 
3
  //   wait for a "C" byte to come back.
4
  //   fill in your server's numerical address below:
5
  Serial.print("C192.168.1.23/80\n");
6
  status = connecting;
7
}

Bei mir kommt da keine Rückmeldung, wenn ich "C192.168.178.53/80\n" 
sende.

Und wenn die Verbindung stand, hat er den GET gesendet:
1
void httpRequest() {
2
  int i = 0;               // generic loop counter
3
  inByte = -1;  
4
  stringPos = 0;
5
  //  Make HTTP GET request. Fill in the path to your version
6
  //  of the CGI script:
7
  Serial.print("GET /~username/scraper.php HTTP/1.1\n");
8
  delay(250);
9
  //  Fill in your server's name:
10
  Serial.print("HOST: www.myserver.com\n\n");
11
  status = requesting;

Spricht was dagegen, als Host hier ebenfalls "192.168.178.53" anzugeben? 
Das muß doch beides mal der selbe Host sein, oder?


Ich hoffe es ist nur eine Kleinigkeit, die mir bis zum Erfolgserlebnis 
fehlt...

Langsam bin ich mir nicht sicher, ob der XPORT die Daten tatsächlich als 
Bridge 1:1 durchreicht. Aber wie kann ich testen, das tatsächlich aus 
der RJ45 kommt? Wireshark wird vermutlich nur was anzeigen, wenn es sich 
um einen "gültigen" Befehl handelt. Vermutlich brächte ich noch einen 
zweiten XPort, den ich mit gekreuztem Kabel anschließe und dort die 
Daten mitlese.

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Matthias schrieb:
> Ich habe nun etliches den ganzen Tag ausprobiert und mich versucht
> einzulesen in das Thema. Aber ich muß ehrlich gestehen, daß ich total
> verwirrt bin. Ich habe gedacht, wenn ich das selbe sende wie der Browser
> beim GET, dann wird der Server schon antworten. So einfach ist es leider
> nicht.

Doch ist so, aber da fehlt hat noch die leere Zeile am Ende. Solange du 
die nicht sendest, wartet der Server auf weitere Request header.

> aber da muß doch sicherlich noch etwas vorher gesendet werden.
> Mir ist aber nicht ganz klar, was.

Lies das PDF, dass ich dir empfohlen habe. Da steht drin, worauf es 
ankommt.

> Serial.print("GET /~username/scraper.php HTTP/1.1\n");
> strcat(caString, "Host: 192.168.178.53\n\n");
> Serial.print("HOST: www.myserver.com\n\n");

Es muss immer \r\n heißen. Ob und wie ein Server auf falsche 
Zeilenumbrüche reagiert, ist nicht spezifiziert.

> Langsam bin ich mir nicht sicher, ob der XPORT die Daten
> tatsächlich als Bridge 1:1 durchreicht.

Richte dir einen lokalen Webserver ein und kontrolliere die 
Kommunikation mit Wireshark.

Oder benutze Netcat um auf einen einzelnen Request zu warten. Wie das 
unter Linux aussieht, wenn ich im Browser http://localhost:8080/test 
aufrufe, habe ich als Bild angehängt.

Nachtrag: Warum wiederhole ich hier eigentlich die Infos aus meinem 
eigenen PDF? Ich hatte es geschrieben, um genau dies nicht tun zu 
müssen.

von Matthias (Gast)


Lesenswert?

@Stefan: zunächst mal Danke für Deine Hilfe!

OK, ich habe nun zweimal "\r\n\r\n" nach dem Hostname, hatte ich zuvor 
auch schon mal ausprobiert, geht aber immer noch nicht:
1
void http_Request(void)
2
{
3
unsigned int uiAnzahlBytes;
4
5
strcpy(caString, "GET /login.htm HTTP/1.1\r\n");
6
strcat(caString, "Host: 192.168.178.53\r\n\r\n");
7
uiAnzahlBytes = strlen(caString);
8
HAL_UART_Transmit_IT(&huart2, caString, uiAnzahlBytes);
9
}

Du meinst sicherlich Kapitel 10.1. Aber das sind ja die 2 Zeilen, die 
ich sende, nun gefolgt von 2 Zeilenumbrüchen. Irgend wie stehe ich auf 
dem Schlauch. Sorry.

Ich benutze aktuell mein neues Ethernetmodul zum Programmieren (Platine 
mit STM32). Als Gegenstelle benutze ich zum Testen meinen alten 
Webserver (noch mit ATMEGA), den ich vor über 10 Jahren mal programmiert 
habe. Er geht problemlos, muß aber nur auf HTTP-Requests entsprechende 
HTML-Quellcode senden. GET Senden habe ich bislang nicht gemacht.
Ich werde Netcat mal morgen probieren. Muß mal suchen, wo es dieses für 
Windows 10 gibt.

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Matthias schrieb:
> Ich hoffe es ist nur eine Kleinigkeit, die mir bis zum Erfolgserlebnis
> fehlt...

Vom prinzipiellen Schichtaufbau her:
- 5-7 Session/Presentation/Application  : HTTP(S)
- 4 Transport  : TCP
- 3 Network  : IP
- 2 Data Link  : Ethernet

Direkt Layer 5 zu Layer 2 geht so nicht.
Du muss dein Teil zumindest dazu bringen überhaupt erstmal eine 
TCP-Connection zum Ziel aufzubauen. Erst wenn diese steht "steht" kannst 
du in den höheren Layer überhaupt dran denken was zu senden. Ob das 
"xport" das alles macht müsstest du im Wireshark sehen können. Wenn es 
dumm läuft musst du dich im Layer 3 auch noch um die MAC-Adressen und so 
kümmern oder gar einen kompletten Frame zusammensetzen.

- 
https://de.wikipedia.org/wiki/Transmission_Control_Protocol#Verbindungsaufbau
- .
- https://de.wikipedia.org/wiki/IP-Paket#IP-Header
- 
https://de.wikipedia.org/wiki/Transmission_Control_Protocol#Aufbau_des_TCP-Headers

von Stefan F. (Gast)


Angehängte Dateien:

Lesenswert?

Matthias schrieb:
> Irgend wie stehe ich auf dem Schlauch. Sorry.

Teste das mal manuell mit Netcat ganz unabhängig von deiner Elektronik. 
Im Angehängten Bild habe ich Google als Webserver aufgerufen. Du kannst 
das ebenso mit deiner IP Adresse machen.

von Stefan F. (Gast)


Lesenswert?

Matthias schrieb:
> Muß mal suchen, wo es dieses für Windows 10 gibt.

Weil es immer wieder woanders ist, habe ich eine Kopie davon auf meine 
eigene Homepage gepackt: 
http://stefanfrings.de/avr_tools/netcat-win32-1.12.zip

Korrektur:
> Teste das mal

Ich meinte, dass du den Web-Server manuell testen sollst. Es bringt ja 
nichts, einen Web-Client zu programmieren, solange nicht klar ist ob und 
wie der Server funktioniert.

von Gerald K. (geku)


Lesenswert?

Die große Frage ist, welche Protokollschichten vom 
Serial-to-Ethernet-Wandler abgewickelt werden.

https://www.ip-insider.de/was-ist-das-osi-modell-a-605831/

Gibt es keine Unterlagen und/oder Programmbeispiele zum 
Serial-to-Ethernet-Wandler?

Wie werden die einzelnen Protokollschichten parameterisiert?
z.B. MAC?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Matthias schrieb:
> strcat(caString, "Host: 192.168.178.53\n\n");  // server

Die Kombination "\n\n" sendet schon eine weitere Leerzeile nach 
"Host:...". Stefan hat das wohl übersehen. Trotzdem würde ich an Deiner 
Stelle konsequent CRLF-Paare schicken, also:
1
strcat(caString, "Host: 192.168.178.53\r\n\r\n");  // server

wie Du es auch später dann probiert hast. Lass das so, das sieht gut 
aus. Dann wird gesendet:
1
GET /login.htm HTTP/1.1<CR><LF>
2
Host: 192.168.178.53<CR><LF>
3
<CR><LF> (also Leerzeile)

Das passt! Aber vorher(!) musst Du natürlich eine TCP-Verbindung 
aufbauen. Sonst weiß Dein Gerät ja gar nicht, wohin es diese Zeilen 
überhaupt schicken soll. Diese Host-Zeile gehört zum HTTP-Protokoll und 
wird von Deinem Serial-Ethernet-Wandler überhaupt nicht inhaltlich 
ausgewertet!

Von daher ist diese Bemerkung:

> Auf der Seite https://www.tigoe.com/pcomp/code/PHP/25/#more-25 hat mich
> verwirrt, daß er erst mal einen Server mit dem XPort connected hat:

wichtig! Du musst erst den Connect machen. Dabei solltest Du die 
IP-Adresse 192.168.178.53 verwenden - wenn das Dein HTTP-Server ist, den 
Du erreichen willst.
1
> void xportConnect() {
2
>   //   send out the server address and
3
>   //   wait for a "C" byte to come back.
4
>   //   fill in your server's numerical address below:
5
>   Serial.print("C192.168.1.23/80\n");
6
>   status = connecting;
7
> }
Im Kommentar lese ich auch, dass Du auf ein "C" (wie "Connected") warten 
sollst. Von daher ist die obige Funktion nicht wirklich vollständig. Es 
kann natürlich sein, dass der Code nach Aufruf von xportConnect() diese 
Abfrage macht. Ich kenne diesen Code nicht.

> Bei mir kommt da keine Rückmeldung, wenn ich "C192.168.178.53/80\n"
> sende.

Das ist schlecht. Ich sehe aber überhaupt keine Abfrage, um die Antwort 
des Geräts auszuwerten, siehe oben. Welche IP hat denn Dein Gerät? 
Stimmen die ersten 3 Oktetts überein?

> Spricht was dagegen, als Host hier ebenfalls "192.168.178.53" anzugeben?

Die Zeile "Host: ...." gehört zum HTTP-Protokoll und sagt dem Server 
lediglich, dass die URL insgesamt "http://192.168.178.53/"; lauten soll. 
Es gibt Webserver, die arbeiten mit virtual Hosts und können auf 
verschiedene IP-Adressen oder verschiedene Namen auch verschiedene 
Seiten ausliefern. Nichts anderes bedeutet hier die Host-Zeile. Du 
solltest daher entweder den Hostnamen Deines Webservers oder die 
IP-Adresse angeben. Man kann sogar für erste Tests auf die Host-Zeile 
verzichten, allerdings muss man trotzdem eine weitere Leerzeile nach 
"GET ..." schicken, also das weitere Paar "\r\n". Dann nimmt der Server 
an, Du meinst den Standard Virtual Host ("Default").

Viel wichtiger ist der Connect auf TCP/IP-Ebene, also der 
"C192.168.178.53\n"-Befehl. Ob der jedoch syntaktisch richtig ist, kann 
ich nicht beurteilen, denn ich kenne Dein Xport-Gerät nicht.

Du hast massive Lücken bei dem Verständnis von IP, TCP/IP und HTTP - in 
dieser Reihenfolge. Lies Dich erstmal in die Thematik ein, bevor Du da 
im Nebel stocherst. Es ist nicht verkehrt, die Protokolle auch zu 
verstehen und zu beherrschen, statt diese einfach nur blind und falsch 
anzuwenden.

Und dann noch als Letztes:

Lies auch die Dokumentation zu Deinem Serial-to-Ethernet-Wandler! Dort 
wird es nicht nur Beispiele geben, sondern da wird bestimmt auch 
erklärt, wie Du vorgehen musst, um Dich mit einem Server zu verbinden. 
Die Beispiele solltest Du ausprobieren und auch versuchen, zu verstehen. 
Sonst wird das nix.

von Matthias (Gast)


Lesenswert?

Gerald K. schrieb:
> Gibt es keine Unterlagen und/oder Programmbeispiele zum
> Serial-to-Ethernet-Wandler?

Unter https://www.lantronix.com/products/xport/ findet man einige 
Dokumente. Aber ehrlich gesagt verstehe ich nicht alles so ganz...

Auf https://cdn.lantronix.com/wp-content/uploads/pdf/XPort_UG.pdf steht 
auf Seite 52 was von "Active Startup". Mein X-Port ist wie folgt 
eingestellt:
Das Register steht auf "0xD4":
- Incoming Connection: Always Accept
- Response: Character response (C=connect, D=disconnect, N=unreachable)
- Active Startup: Manual connection

Das mit dem Senden von "C192.168.178.53/80\n" sollte daher eigentlich 
gehen. Nur es kommt keine Antwort vom X-Port zurück.

von Matthias (Gast)


Lesenswert?

Nachtrag: Die Rückantwort vom X-Port sehe ich im Empfangsbuffer des 
Debuggers.

von Stefan F. (Gast)


Lesenswert?

Vergiss vorläufig deinen XPort, teste das erst manuell mit Netcat.
1
> nc -v 192.168.178.53 80
2
Connection to 192.168.178.53 80 port [tcp/http] succeeded!

Bekommst du damit eine Verbindung zum Server? Wenn nicht, ist der Server 
oder die Verbindung dorthin kaputt. Oder der IP/Port sind falsch.

Wenn verbunden, gebe dann das ein:
1
GET /login.htm HTTP/1.0<Enter>
2
<Enter>

Dann müsste eine HTML Seite oder wenigstens eine Fehlermeldung zurück 
kommen. Wenn nicht, ist der Server kaputt.

von Irgend W. (Firma: egal) (irgendwer)


Lesenswert?

Matthias schrieb:
> Unter https://www.lantronix.com/products/xport/ findet man einige
> Dokumente.

Das Teil kann zumindest schon mal einiges:

Network Interface
- Interface: Ethernet 10Base-T or 100Base-TX (Auto-Sensing)
- Protocols: TCP/IP, UDP/IP, ARP, ICMP, SNMP, TFTP, Telnet, DHCP, BOOTP, 
HTTP, and AutoIP

Management
- SNMP, Telnet, serial, internal web server, and Microsoft Windows®- 
based utility for configuration

Aus dem Handbuch:

Assigning an IP Address
The unit’s IP address must be configured before it can work correctly on 
a network. You have several options for assigning an IP to your unit. We 
recommend that you manually assign the IP address over the network using 
DeviceInstaller.

usw...

Hast du das Teil überhaupt richtig Konfiguriert? Kannst du es von einem 
anderen Gerät aus erreichen?

von Matthias (Gast)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Vergiss vorläufig deinen XPort, teste das erst manuell mit Netcat.

Danke Dir für Deine Hilfsbereitschaft!

Ich habe nun Netcat von Dir verwendet. Wenn ich die Daten so eingebe, 
geht das Fenster sofort nach Drücken der Entertaste zu. Ohne das ">" zu 
beginn, dauert es 1-2 Sekunden, bevor das Fenster verschwindet. Stürzt 
da was ab oder soll das Absicht sein?

DIE GUTE NACHRICHT:

Das  connecten geht nun. Ich habe mich selbst verarscht, das 
Empfangsarray wurde an anderer Stelle versehentlich an ein paar Stellen 
modifiziert. Nach dem Booten kommt ein "D" und nach dem Connecten nun 
auch ein "C", wie es sein soll.
1
void xport_connect(void)
2
{
3
unsigned int uiAnzahlBytes;
4
strcpy(web.caHTML_string, "C192.168.178.53/80\n");
5
uiAnzahlBytes = strlen(web.caHTML_string);
6
HAL_UART_Transmit_IT(&huart2, web.caHTML_string, uiAnzahlBytes);
7
}



Auch das Senden des HTTP-Requests geht nun:
1
{
2
unsigned int uiAnzahlBytes;
3
strcpy(caString, "GET /login.htm HTTP/1.1\r\n");
4
strcat(caString, "Host: 192.168.178.53\r\n");
5
strcat(caString, "\r\n");
6
uiAnzahlBytes = strlen(caString);
7
HAL_UART_Transmit_IT(&huart2, caString, uiAnzahlBytes);
8
}

Ohne Eure Hilfe wäre ich aufgeschmissen gewesen. Danke an alle 
Beteiligten!

von Stefan F. (Gast)


Lesenswert?

Öffnet zuerst ein Fenster "Eingabeaufforderung" und tippe dort die 
netcat Befehle ein. Dann schließt es sich nicht und dann kannst du die 
Ergebnisse sehen.

> Ohne das ">" zu beginn

Das sollst du nicht eingeben, das ist die Eingabeaufforderung (von 
Linux) das ich bitte einen Befehl eingeben soll. Gibt's bei Windows auch 
so ähnlich.

Schön dass es nun trotzdem klappt, solche Rückmeldungen werden oft 
vergessen.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Matthias schrieb:
> Ohne das ">" zu beginn

Du hast damit ziemlich sicher versehentlich eine Datei "nc" (ohne 
Endung) im aktuellen Verzeichnis angelegt. Größe: 0 Bytes.

Die kannst Du wieder löschen.

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.