Zum Inhalt
wannacode

Wie das Internet funktioniert

Kurz gesagt: Das Internet ist ein Netz aus Netzen: Eine Seite reist in Paketen zwischen IP-Adressen, DNS macht aus dem Namen der Website eine Adresse, und Browser und Server sprechen über HTTP miteinander.

Problem

Zwischen Enter und der Seite

Du tippst shop.example.bg in den Browser, drückst Enter, und eine halbe Sekunde später siehst du den Katalog mit Kaffee und Tee. Die Seite liegt auf einem Computer in einer anderen Stadt, vielleicht in einem anderen Land. Wie findet der Browser sie? Woher weiß er, dass du den Katalog willst und nicht den Warenkorb? Was genau sagen sich die beiden Programme?

In der nächsten Lektion schreibst du einen Server, der dem Browser antwortet. Dafür musst du die Sprache kennen, in der die beiden sprechen.

Die Idee

Pakete, Router und IP-Adressen

Das Internet ist ein Netz aus Netzen: dein Router zu Hause, das Netz deines Anbieters, die Netze von Ländern und Rechenzentren, alle miteinander verbunden.

  • Daten reisen nicht in einem Stück. Sie werden in Pakete aufgeteilt, kleine Teile von etwa 1500 Bytes. Jedes Paket trägt die Adresse, für die es bestimmt ist.
  • Ein Router ist ein Gerät, das ein Paket empfängt und an das nächste Netz auf dem Weg weiterschickt. Ein Paket geht durch 10 bis 20 Router, und jeder bringt es seinem Ziel näher.
  • Eine IP-Adresse ist die Nummer eines Geräts im Netz, zum Beispiel 93.184.215.14. Dein eigener Computer heißt immer auch localhost (127.0.0.1).
  • Ein Port ist eine Zahl von 0 bis 65 535 für ein Programm auf diesem Computer. Die IP-Adresse ist das Haus, der Port die Wohnung. Webserver lauschen meist auf 80 (HTTP) und 443 (HTTPS).

Die Regeln, wie gesprochen wird, heißen Protokolle. IP liefert einzelne Pakete, verspricht aber nicht, dass sie ankommen. TCP baut auf IP auf: Es stellt eine Verbindung zwischen zwei Programmen her, nummeriert die Pakete, bringt sie in die richtige Reihenfolge und schickt verlorene noch einmal. Deshalb heißen die beiden zusammen TCP/IP.

Genauer, für Neugierige
  • Adressen wie 93.184.215.14 sind IPv4: vier Zahlen von 0 bis 255, etwa 4 Milliarden Adressen. Das reicht nicht, also gibt es auch IPv6: 2606:2800:21f:cb07:6820:80da:af6b:8b2c.
  • Neben TCP gibt es UDP: keine Verbindung und kein erneutes Senden von Verlorenem, dafür schneller. Es wird für Sprache und Video live und für Spiele verwendet. Das Web läuft über TCP.
  • Die beiden Enden einer TCP-Verbindung heißen Sockets: eine Adresse und ein Port auf jeder Seite. Der Port des Browsers wird automatisch aus den freien gewählt.

Die Idee

Ein Name statt einer Zahl: DNS

Menschen merken sich Namen, Computer suchen nach IP-Adresse. Eine Domain ist der menschliche Name einer Website: shop.example.bg. DNS (Domain Name System) macht aus dem Namen eine Adresse:

  1. Der Browser fragt den DNS-Server des Anbieters: „Wie lautet die Adresse von shop.example.bg?“
  2. Wenn er es nicht weiß, fragt er die Kette entlang: den Server für .bg, dann den Server von example.bg.
  3. Die Antwort ist eine IP-Adresse. Der Browser merkt sie sich eine Weile und fragt beim nächsten Mal nicht.

Erst dann verbindet sich der Browser über TCP mit dieser Adresse, auf Port 443.

Die ganze Reise einer Seite, mit dem Teil der Adresse, den jeder Schritt verwendet:

Uri address = new Uri("https://shop.example.bg/products?category=coffee");
Console.WriteLine("1. DNS: Wie lautet die Adresse von " + address.Host + "?");
Console.WriteLine("2. TCP: Verbindung zu Port " + address.Port);
Console.WriteLine("3. HTTP: GET " + address.PathAndQuery);
Schritt für Schritt, in Worten
  1. Die Adresse sagt alles Nötige: welches Protokoll, welcher Computer und welche Ressource.
  2. Zuerst der Name: Der Browser fragt DNS nach der IP-Adresse von shop.example.bg.
  3. DNS antwortet mit einer IP-Adresse, zum Beispiel 93.184.215.14. Der Browser merkt sie sich.
  4. Eine TCP-Verbindung zu dieser Adresse. Der Port steht nicht in der Adresse, also ist es 443, der für https.
  5. Über die Verbindung geht eine HTTP-Anfrage: die Methode GET und der Pfad /products?category=coffee.
  6. Der Server antwortet: Status 200 OK und HTML. Der Browser zeichnet die Seite.
  7. Drei Schritte: ein Name wird zur Adresse (DNS), eine Verbindung (TCP), eine Anfrage und eine Antwort (HTTP).

Hosting ist der Computer, auf dem die Website lebt: ein Server in einem Rechenzentrum, immer an und verbunden. Die Domain zeigt auf das Hosting: DNS sagt „shop.example.bg ist unter dieser IP-Adresse“.

Genauer, für Neugierige
  • Eine Domain registrierst du gegen eine jährliche Gebühr bei einem Registrar: einer Firma, die für diese Endung (.bg, .com, .eu) zugelassen ist. Die Registrierung gilt für eine feste Zeit, meist ein Jahr, und du verlängerst sie. Wenn du sie nicht verlängerst, wird der Name frei, und jeder kann ihn nehmen. Eine gute Domain ist kurz, leicht zu merken und sagt, wofür die Website da ist.
  • Es gibt mehrere Arten von Hosting. Shared: viele Websites auf einem Server, günstig, aber die Nachbarn beeinflussen dich. VPS (virtueller privater Server): dein eigener Teil eines Servers mit garantierten Ressourcen. Cloud: Du zahlst, was du verbrauchst, und wächst, wenn du es brauchst. Dedizierter Server: eine ganze Maschine nur für dich. Die Wahl hängt vom Verkehr, von den nötigen Ressourcen und vom Budget ab.

Sieh es dir an

Die Adresse und ihre Teile

Die Adresse einer Seite heißt URL (Uniform Resource Locator). Sie sagt alles, was nötig ist, um zur Seite zu kommen. In der Dokumentation triffst du auch den allgemeineren Namen URI (Uniform Resource Identifier), daher kommt der Name der Klasse. In C# gibt dir die Klasse Uri die Teile:

Uri address = new Uri("https://shop.example.bg:8443/products?category=coffee&page=2");
Console.WriteLine("Schema: " + address.Scheme);
Console.WriteLine("Host: " + address.Host);
Console.WriteLine("Port: " + address.Port);
Console.WriteLine("Pfad: " + address.AbsolutePath);
Console.WriteLine("Query: " + address.Query);
Uri home = new Uri("https://shop.example.bg/");
Console.WriteLine("Standardport: " + home.Port);
Ausgabe
Schema: https
Host: shop.example.bg
Port: 8443
Pfad: /products
Query: ?category=coffee&page=2
Standardport: 443
  • Schema (https): welches Protokoll.
  • Host (shop.example.bg): welcher Computer. Der Name geht durch DNS.
  • Port (8443): welches Programm darauf. Wenn er nicht in der Adresse steht, ist es der Standardport des Schemas: 443 für https, 80 für http.
  • Pfad (/products): welche Ressource auf dem Server.
  • Query (?category=coffee&page=2): zusätzliche Parameter als Paare name=value, getrennt durch &.

Was gibt das Programm aus?

Uri cart = new Uri("http://shop.example.bg/cart?step=2");
Console.WriteLine(cart.Port + " " + cart.AbsolutePath);
Antwort
Genauer, für Neugierige
  • Eine Adresse darf nur lateinische Buchstaben, Ziffern und einige Zeichen enthalten. Alles andere, etwa Buchstaben mit Akzent und Leerzeichen, wird als UTF-8-Bytes mit einem % davor geschrieben. Der Browser zeigt dir „Café Crème“, aber über das Netz geht die kodierte Form:
Uri search = new Uri("https://shop.example.bg/search?q=Café Crème");
Console.WriteLine(search.AbsoluteUri);
Console.WriteLine(Uri.UnescapeDataString(search.Query));
Ausgabe
https://shop.example.bg/search?q=Caf%C3%A9%20Cr%C3%A8me
?q=Café Crème
  • Nach dem Pfad kann auch ein Fragment stehen: #reviews. Es erreicht den Server nie: Der Browser scrollt die Seite nur zu diesem Teil.

Die Idee

Eine HTTP-Anfrage

Der Browser hat sich verbunden. Jetzt schickt er eine HTTP-Anfrage (Request; HyperText Transfer Protocol). Die Anfrage ist Text:

Anfrage
GET /products?category=coffee HTTP/1.1
Host: shop.example.bg
Accept: text/html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/131.0
  • Die erste Zeile ist die Methode, der Pfad und die Version. Die Methode sagt, was du willst: GET ist „gib mir“, POST ist „hier sind Daten“ (eine Bestellung, ein Formular). Es gibt auch PUT (ersetzen), DELETE (löschen) und andere.
  • Dann kommen die Header, einer pro Zeile: name: value. Host sagt, welche Website du willst, weil ein Server viele Websites beherbergen kann. Accept sagt, was der Browser versteht, und User-Agent, wer er ist.
  • Eine Leerzeile beendet die Header. Danach kann ein Body kommen: die Daten der Anfrage. GET hat keinen Body, POST meistens schon:
Anfrage mit Body
POST /cart HTTP/1.1
Host: shop.example.bg
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
product=C-101&qty=2

Content-Length sagt, wie viele Bytes der Body hat, damit der Server weiß, wann er alles empfangen hat.

Die Idee

Eine HTTP-Antwort

Der Server antwortet mit derselben Art von Text (Response). Die erste Zeile trägt den Status: eine Zahl und eine kurze Erklärung. Die erste Ziffer sagt dir die Art:

Status Art Beispiel
2xx Erfolg 200 OK: Hier ist, was du wolltest
3xx Weiterleitung 301 Moved Permanently: Es ist jetzt unter einer anderen Adresse
4xx Fehler in der Anfrage 404 Not Found: So etwas gibt es nicht
5xx Fehler auf dem Server 500 Internal Server Error: Das Programm auf dem Server ist gescheitert

Danach kommen die Header der Antwort und der Body: das HTML der Seite, JSON mit Daten, ein Bild.

Antwort
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Content-Length: 37
<h1>Dieses Produkt gibt es nicht</h1>

Content-Type sagt, was der Body ist und in welcher Kodierung. Bei einer Weiterleitung gibt der Header Location die neue Adresse an, und der Browser schickt von selbst eine neue Anfrage dorthin:

Weiterleitung
HTTP/1.1 301 Moved Permanently
Location: https://shop.example.bg/products
Genauer, für Neugierige
  • HTTP hat kein Gedächtnis (es ist zustandslos, stateless): Jede Anfrage steht für sich, und der Server erinnert sich nicht an die früheren. Damit die Website sich im Warenkorb an dich „erinnert“, gibt sie dir ein Cookie: einen Header, den der Browser bei jeder folgenden Anfrage zurückschickt.
  • Ein DDoS-Angriff über HTTP nutzt genau dieses fehlende Gedächtnis: Tausende infizierte Computer schicken eine riesige Zahl von Anfragen an einen Server. Jede sieht normal aus, und der Server muss sie bearbeiten, bis er auch mit den echten Kunden nicht mehr mitkommt. Die Abwehr sitzt vor dem Server: Dienste, die verdächtigen Verkehr filtern und die Zahl der Anfragen von einer Adresse begrenzen.

Sieh es dir an

Die Antwort, mit Code zerlegt

Eine Antwort ist nur Text, also kannst du sie mit String-Methoden zerlegen. Jede Zeile in HTTP endet mit \r\n, und die Leerzeile zwischen Headern und Body ist \r\n\r\n:

string response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"Content-Length: 21\r\n" +
"\r\n" +
"<h1>Café Crème</h1>";
string[] parts = response.Split("\r\n\r\n");
string[] lines = parts[0].Split("\r\n");
string[] status = lines[0].Split(' ', 3);
Console.WriteLine("Version: " + status[0]);
Console.WriteLine("Status: " + status[1] + " (" + status[2] + ")");
Dictionary<string, string> headers = new Dictionary<string, string>();
for (int i = 1; i < lines.Length; i++)
{
string[] header = lines[i].Split(": ", 2);
headers[header[0]] = header[1];
}
Console.WriteLine("Typ: " + headers["Content-Type"]);
Console.WriteLine("Länge: " + headers["Content-Length"] + " Bytes");
Console.WriteLine("Body: " + parts[1]);
Ausgabe
Version: HTTP/1.1
Status: 200 (OK)
Typ: text/html; charset=utf-8
Länge: 21 Bytes
Body: <h1>Café Crème</h1>
  • Split("\r\n\r\n") teilt sie in zwei: den Header-Teil und den Body.
  • Der Header-Teil wird in Zeilen geteilt. Die erste ist der Status. Split(' ', 3) gibt höchstens 3 Teile: So bleibt bei 404 Not Found die Erklärung ganz.
  • Die Header kommen in ein Dictionary: Name → Wert. Split(": ", 2) teilt nur beim ersten : .

Jedes Programm, das HTTP spricht, arbeitet so. In der nächsten Lektion erledigt HttpClient das für dich.

Genauer, für Neugierige
  • Content-Length ist 21 Bytes, aber der Text hat 19 Zeichen. Über das Netz reisen UTF-8-Bytes, und dort braucht jeder Buchstabe mit Akzent, wie é oder è, 2 Bytes:
string body = "<h1>Café Crème</h1>";
Console.WriteLine(body.Length + " Zeichen");
Console.WriteLine(System.Text.Encoding.UTF8.GetByteCount(body) + " Bytes");
Ausgabe
19 Zeichen
21 Bytes
  • Header-Namen hängen nicht von Groß- und Kleinschreibung ab: content-type und Content-Type sind dasselbe. Ein Dictionary, das so vergleicht, baust du mit new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase).
  • HTTP/1.1 ist Text. Die neueren HTTP/2 und HTTP/3 schicken dieselben Methoden, Header und Status, aber in binärer Form und mit vielen Anfragen über eine Verbindung. Für dein Programm ist die Bedeutung dieselbe.

Probier es aus

Ein Header mit Doppelpunkt

Das Programm soll Name und Wert des Headers ausgeben, aber statt der Adresse gibt es nur https aus. In welcher Zeile ist der Fehler?

Wähle die Zeile mit dem Fehler.

Die Idee

HTTPS: dasselbe, aber abgeschlossen

HTTP ist reiner Text. Jeder Router auf dem Weg kann dein Passwort lesen oder den Preis ändern. HTTPS ist HTTP über TLS (der ältere Name ist SSL):

  1. Handshake. Browser und Server einigen sich, wie verschlüsselt wird, und tauschen Schlüssel aus.
  2. Zertifikat. Der Server zeigt ein Zertifikat, unterschrieben von einer Organisation, der der Browser vertraut. So weißt du, dass du mit dem echten shop.example.bg sprichst und nicht mit jemandem dazwischen.
  3. Verschlüsselung. Ab dann reisen Anfragen und Antworten verschlüsselt. Unterwegs sieht jeder, zu welchem Server du gehst, aber nicht, was ihr euch sagt.

Methoden, Header und Status sind dieselben wie bei HTTP. Das Schloss in der Adressleiste bedeutet, dass die Verbindung über HTTPS läuft.

Die Idee

Was der Browser tut

Die erste Antwort ist HTML: der Text und die Struktur der Seite. Der Browser liest es und findet darin weitere Ressourcen: Stile (CSS), Programme (JavaScript), Bilder, Schriften. Für jede schickt er eine neue Anfrage. Eine gewöhnliche Seite macht Dutzende Anfragen, bevor sie fertig ist. Deshalb lädt eine Website mit vielen schweren Bildern langsam, auch wenn ihr HTML klein ist.

Dann ordnet der Browser alles an und zeichnet es auf den Bildschirm. JavaScript kann die Seite danach ändern, ohne sie neu zu laden.

Genauer, für Neugierige
  • Ein Browser hat mehrere Teile. Die Benutzeroberfläche: die Adressleiste, die Buttons, die Lesezeichen, alles außer der Seite selbst. Die Browser-Engine verbindet die Oberfläche mit der Rendering-Engine, die HTML und CSS versteht und zeichnet. Der Netzwerkteil macht die HTTP-Anfragen. Eine Zeichenschicht für einfache Steuerelemente (Aufklapplisten, Fenster), auf allen Betriebssystemen gleich. Der JavaScript-Interpreter führt die Skripte aus. Der Speicher hält Cookies und Daten der Websites (localStorage, IndexedDB).
  • Wie das Zeichnen funktioniert: Aus dem HTML baut der Browser einen Baum der Elemente (das DOM), aus dem CSS einen Baum der Stile (das CSSOM). Zusammen ergeben die beiden den Render-Baum. Dann berechnet er, wo jedes Element hinkommt und wie groß es ist (Layout), und zum Schluss zeichnet er (Paint). JavaScript ändert das DOM, und der Browser zeichnet nur das neu, was betroffen ist.
  • Zum Weiterlesen: Wie das Internet funktioniert, Ein Überblick über HTTP, Wie Browser funktionieren und HTTP-Flood-DDoS-Angriffe.

Übung

Adressen, Status und Anfragen

Löse die Aufgaben in deinem Editor.

1. Teile einer Adresse. Gib für https://shop.example.bg/search?q=espresso&max=30&page=2 Host, Port und Pfad aus. Dann teile die Query in Paare in einem Dictionary (TrimStart('?') entfernt das Fragezeichen, dann Split('&') und Split('=')), gib sie aus und hol die Seitenzahl als Zahl:

Ausgabe
Host: shop.example.bg, Port 443
Pfad: /search
q = espresso
max = 30
page = 2
Seite: 2

2. Was der Status bedeutet. Eine Methode Meaning(int code) mit einem switch gibt die Bedeutung der bekannten Codes 200, 201, 301, 404 und 500 zurück. Für die anderen gibt sie die Art nach der ersten Ziffer (code / 100), und für eine unbekannte Art gibt sie „unbekannter Code“ zurück:

Ausgabe
200: Erfolg
201: erstellt
301: dauerhaft verschoben
404: keine solche Ressource
418: Fehler in der Anfrage
500: Serverfehler
503: anderer Serverfehler

3. Bau eine Anfrage. Eine Methode BuildGet(Uri address) gibt den Text einer GET-Anfrage mit Host und Accept: text/html zurück, mit \r\n am Ende jeder Zeile und einer Leerzeile am Schluss. address.PathAndQuery gibt den Pfad zusammen mit der Query. Gib sie aus und ersetze dabei jedes \r\n durch den sichtbaren Text \r\n und einen Zeilenumbruch:

Ausgabe
GET /products?category=tea HTTP/1.1\r\n
Host: shop.example.bg\r\n
Accept: text/html\r\n
\r\n

Test

Teste dich

1. Was macht DNS?
2. Welcher Port ist es in der Adresse https://shop.example.bg/products?category=tea?
3. Die Antwort hat den Status 404. Was bedeutet das?
4. Woran erkennt der Client, wo in einer Antwort die Header enden und der Body beginnt?
5. Was fügt HTTPS zu HTTP hinzu?

Erstellt von Ivo Gergov im Rahmen der Kampagne von Evo Tech für zugängliche Programmierausbildung ·