Das OSI-Modell wirklich verstehen — eine einzelne HTTP-Anfrage in ihre sieben Schichten zerlegen
· Go Komura · OSI-Modell, TCP/IP, Netzwerke, Wireshark, Ethernet, TCP, HTTP, C#, .NET, Socket, Technische Beratung
Das OSI-Modell ist das Erste, was in jedem Einsteigerbuch zu Netzwerken auftaucht — und doch hört man immer wieder denselben Satz: „Ich kann die Namen der sieben Schichten aufsagen, aber ehrlich gesagt habe ich kein wirkliches Gefühl dafür.“ Man lernt Bitübertragungsschicht, Sicherungsschicht, Vermittlungsschicht … auswendig, ohne dass sich je eine Verbindung zwischen diesem siebenstufigen Diagramm und dem eigenen C#-Code oder der gerade vor einem liegenden Netzwerkstörung einstellt.
Auf diesem Blog haben wir bisher schon Artikel zum Verhalten von L4 (der Transportschicht) veröffentlicht — etwa zum Missverständnis, dass man über TCP in denselben Einheiten empfangen kann, in denen man gesendet hat und zur Ursache und Eingrenzung von Kommunikationsabbrüchen bei Industriekameras durch TCP-Neuübertragungen — aber einen Artikel, der das zugrunde liegende Konzept der „Schicht“ selbst zusammenfasst, gab es bisher nicht.
Der Ansatz dieses Artikels ist einfach. Wir bauen tatsächlich einen einzelnen Ethernet-Frame, der eine einzelne HTTP-GET-Anfrage trägt, und zerlegen ihn von außen nach innen. Die sieben Schichten sind nicht nur etwas in einem konzeptionellen Diagramm — sie existieren physisch, verschachtelt in den 171 Bytes, die über das Netzwerk fließen. Sobald Sie das mit eigenen Augen im Hexdump und in Wireshark sehen, hört das OSI-Modell auf, etwas zu sein, das man auswendig lernt.
Der in diesem Artikel gezeigte Code ist als vollständiges, build- und lauffähiges Beispielpaket auf GitHub veröffentlicht (eine Bibliothek zum Zusammenbauen und Zerlegen von Frames, der Export einer pcap-Datei, die sich in Wireshark öffnen lässt, sowie Unit-Tests).
osi-model-packet-anatomy - komurasoft-blog-samples (GitHub)
1. Das Wichtigste zuerst
- Das OSI-Modell ist ein „Vokabular“, keine „Implementierung“. Was im realen Internet tatsächlich läuft, ist die TCP/IP-Protokollsuite (effektiv vier Schichten); die eigentlichen 7-Schichten-Protokolle von OSI haben das Rennen um die Verbreitung verloren und werden nicht genutzt. Überlebt hat das Modell als gemeinsame Sprache — Formulierungen wie „lass uns das auf L2 eingrenzen“ oder „das ist ein L7-Problem“.12
- Die sieben Schichten sind physisch als Byte-Folge ineinander verschachtelt. Bei einem Frame, der ein HTTP GET trägt, sind die ersten 14 Bytes der Ethernet-Header (L2), die nächsten 20 Bytes der IPv4-Header (L3), die nächsten 20 Bytes der TCP-Header (L4) und der Rest der HTTP-Text (L7). Dass der Header jeder Schicht unmittelbar dort beginnt, wo die vorherige endet, lässt sich direkt im Hexdump dieses Artikels und in Wireshark nachvollziehen.
- Was Ihr C#-Code direkt schreibt, ist ausschließlich die Byte-Folge von L7. An
Socket.Sendwird nur Anwendungsdaten übergeben; die TCP- und IP-Header fügt der Protokoll-Stack des Betriebssystems hinzu, den Ethernet-Header und das elektrische Signal die NIC. Genau deshalb ist die Wahl zwischenHttpClient,SslStreamundSocketeine Entscheidung darüber, „welche Schicht und alles darunter man dem Betriebssystem überlässt“.3 - L5 (die Sitzungsschicht) und L6 (die Darstellungsschicht) existieren im realen Stack nicht als eigenständige Schichten. TLS und Zeichenkodierung übernehmen einen Teil dieser Rolle, gelten im TCP/IP-Modell aber gemeinsam als Anwendungsschicht. Wenn Sie „nicht verstehen, was L6 sein soll“, liegt das nicht an Ihnen — genau hier klaffen Modell und Realität auseinander.2
- Wo sich das OSI-Modell in der Praxis wirklich auszahlt, ist bei der Fehlersuche und im Gespräch. Eingrenzungen mit dem Vokabular der Schichten — etwa „der Ping geht durch, aber HTTP schlägt fehl, also lebt L3 noch und man sollte L4 oder höher verdächtigen“ — werden zu einer gemeinsamen Sprache zwischen Netzwerk-, Infrastruktur- und App-Entwicklern.
2. Warum das OSI-Modell zum reinen Auswendiglernen wird
Die meisten Erklärungen beginnen mit einer solchen Tabelle.
| Schicht | Name | Beschreibung |
|---|---|---|
| L7 | Anwendungsschicht | Stellt Anwendungen Kommunikationsdienste bereit |
| L6 | Darstellungsschicht | Wandelt das Darstellungsformat der Daten um |
| L5 | Sitzungsschicht | Verwaltet Beginn und Ende einer Kommunikation |
| L4 | Transportschicht | Stellt eine zuverlässige Datenübertragung bereit |
| L3 | Vermittlungsschicht | Übernimmt Routenwahl und Adressierung |
| L2 | Sicherungsschicht | Überträgt Daten zwischen benachbarten Knoten |
| L1 | Bitübertragungsschicht | Wandelt Bits in elektrische Signale um |
Diese Tabelle ist korrekt, aber da jede Zeile in abstrakten Begriffen formuliert ist, entsteht beim Lesen kein konkretes Bild. Sagt man jemandem „wandelt das Darstellungsformat der Daten um“, wird niemand sagen können, welche Zeile im eigenen Code damit gemeint ist.
Es gibt noch eine historische Tatsache, die man offen ansprechen sollte. Das OSI-Modell ist ein von der ISO (Internationale Organisation für Normung) und der ITU-T festgelegter Standard (ISO/IEC 7498-1, ITU-T X.200) und war ursprünglich als groß angelegtes Konzept gedacht, zu dem passend für jede der sieben Schichten ein eigenes OSI-Protokoll gehören sollte.1 Im Verbreitungswettbewerb der 1990er-Jahre setzte sich jedoch TCP/IP, das bereits funktionierende Implementierungen vorweisen konnte, faktisch als Standard durch, und die OSI-Protokolle selbst wurden am Ende kaum genutzt. RFC 1122, das die Grundlage des Internets festlegt, erklärt die Welt anhand von effektiv vier Schichten — Verbindungsschicht, Internetschicht (IP), Transportschicht und Anwendungsschicht — und kennt keine eigenständigen Schichten, die L5 oder L6 entsprechen.2
Mit anderen Worten: Der Grund, warum wir das OSI-Modell heute noch lernen, ist nicht, „weil so implementiert wird“, sondern um das Werkzeug „in Schichten denken“ und ein gemeinsames Vokabular für die Fehlersuche zu gewinnen. Geht man von dieser Prämisse aus, muss man sich nicht mehr darüber den Kopf zerbrechen, dass sich „das reale Gegenstück zu L5 und L6 nicht finden lässt“, und alles wird auf einen Schlag klarer.
3. Zur Sache: Eine einzelne HTTP-Anfrage zerlegen
Genug der Vorrede — schauen wir uns die Sache konkret an. Der folgende Hexdump zeigt einen Ethernet-Frame (insgesamt 171 Bytes), der eine einzelne HTTP-Anfrage, GET /index.html HTTP/1.1, trägt. Er wurde vom eingangs vorgestellten Beispielcode zusammengebaut, und da sowohl die IPv4-Header-Prüfsumme als auch die TCP-Prüfsumme korrekt berechnet sind, zeigt Wireshark ihn beim Einlesen als ganz normales Paket an.
0000 02 00 00 00 00 01 02 00 00 00 00 02 08 00 45 00 ..............E.
0010 00 9d 12 34 40 00 40 06 3b 99 c0 00 02 0a c6 33 ...4@.@.;......3
0020 64 50 cb 84 00 50 00 00 03 e8 00 00 07 d0 50 18 dP...P........P.
0030 ff ff a3 05 00 00 47 45 54 20 2f 69 6e 64 65 78 ......GET /index
0040 2e 68 74 6d 6c 20 48 54 54 50 2f 31 2e 31 0d 0a .html HTTP/1.1..
0050 48 6f 73 74 3a 20 65 78 61 6d 70 6c 65 2e 63 6f Host: example.co
0060 6d 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a 20 4b m..User-Agent: K
0070 6f 6d 75 72 61 53 6f 66 74 44 65 6d 6f 2f 31 2e omuraSoftDemo/1.
0080 30 0d 0a 41 63 63 65 70 74 3a 20 74 65 78 74 2f 0..Accept: text/
0090 68 74 6d 6c 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e html..Connection
00a0 3a 20 63 6c 6f 73 65 0d 0a 0d 0a : close....
Betrachtet man die ASCII-Darstellung auf der rechten Seite, sieht man, dass ab einer bestimmten Stelle (Offset 0x36) für Menschen lesbarer Text beginnt: GET /index.html HTTP/1.1. Was aber sind die 54 Bytes davor? Füttert man sie in den Zerleger (Dissector) des Beispiels, meldet dieser Folgendes.
[ L2 Ethernet II | offset 0 | 14 bytes | dst=02:00:00:00:00:01 src=02:00:00:00:00:02 type=0x0800 (IPv4)
[ L3 IPv4 | offset 14 | 20 bytes | 192.0.2.10 -> 198.51.100.80 TTL=64 proto=6 (TCP) checksum=OK
[ L4 TCP | offset 34 | 20 bytes | 52100 -> 80 [Psh, Ack] seq=1000 win=65535
[ L7 HTTP | offset 54 | 117 bytes | GET /index.html HTTP/1.1
Das ist die Darstellung, die ich in diesem Artikel am meisten sehen lassen möchte. Es gibt drei zentrale Punkte.
- Jede Schicht beginnt unmittelbar dort, wo die vorherige endet. Der Ethernet-Header liegt bei Byte 0–13, der IPv4-Header bei Byte 14–33, der TCP-Header bei Byte 34–53, und HTTP beginnt bei Byte 54. Eine Schicht ist keine begriffliche Kategorie — man kann sie als Byte-Bereich ab dem Frame-Anfang konkret benennen.
- Eine innere Schicht ist für die äußere Schicht nichts weiter als deren „Nutzlast“ (Fracht). Aus Sicht von Ethernet ist alles ab IPv4 einfach nur Fracht — ob der Inhalt TCP ist oder nicht, interessiert es nicht. Aus Sicht von IP ist alles ab TCP die Fracht, aus Sicht von TCP ist HTTP die Fracht. Jede Schicht liest nur ihren eigenen Header und reicht die Fracht unangetastet nach oben weiter. Genau diese Struktur des „Nicht-Kümmerns“ ist Kapselung.
- L1 (die Bitübertragungsschicht) sowie L5 und L6 tauchen in dieser Darstellung nicht auf. L1 hat die Aufgabe, diese Byte-Folge in elektrische Signale, Licht oder Funkwellen umzuwandeln, taucht also im Dump nicht auf, und L5/L6 haben, wie im vorigen Kapitel erklärt, bei unverschlüsseltem HTTP/1.1 keine eigenständige Entsprechung. „Von sieben Schichten tauchen nur vier im Dump auf“ — das ist die reale Situation.
Noch einmal: Das liegt nicht daran, dass HTTP etwas Besonderes wäre. Ob Datenbankverbindung, gRPC oder GigE Vision bei einer Industriekamera — solange es sich um TCP/IP-Kommunikation über Ethernet handelt, hat jedes einzelne Paket diese exakt gleiche verschachtelte Struktur. Es ändert sich nur der Inhalt der L7-Fracht.
4. L2, die Sicherungsschicht — Zustellung „zum Nachbarn“
Gehen wir die Ergebnisse der Zerlegung von außen nach innen durch. Die ersten 14 Bytes sind der Ethernet-II-Header.
02 00 00 00 00 01 Ziel-MAC-Adresse (6 Bytes)
02 00 00 00 00 02 Quell-MAC-Adresse (6 Bytes)
08 00 EtherType = 0x0800 (Fracht ist IPv4)
Die Aufgabe von L2 besteht darin, „innerhalb desselben Netzwerksegments zum benachbarten Knoten zuzustellen“. Zur Angabe des Ziels wird die MAC-Adresse verwendet. Eine MAC-Adresse ist eine der NIC zugewiesene Kennung und erreicht grundsätzlich nicht über einen Router hinweg den eigentlichen Kommunikationspartner. Bei einem Frame, der von einem Büro-PC an einen Webserver gesendet wird, ist die Ziel-MAC-Adresse nicht die des Webservers, sondern die des Standardgateways (Routers).
An dieser Stelle fragen sich viele mindestens einmal: „Wenn es schon eine IP-Adresse gibt, wozu braucht man dann noch eine MAC-Adresse?“ Die Antwort liegt in der Aufteilung der Verantwortung zwischen den Schichten. Die IP-Adresse ist die Adresse, die auf das „endgültige Ziel“ zeigt, die MAC-Adresse die Kennzeichnung dessen, der „den nächsten einzelnen Abschnitt transportiert“. Um es mit einem Paketdienst zu vergleichen: Die IP-Adresse ist die Zieladresse auf dem Versandschein, die MAC-Adresse der Name des „nächsten Verteilzentrums“. Der Versandschein (L3) ändert sich bis zum Schluss nicht, die Kennzeichnung (L2) wird aber auf jedem Abschnitt neu angebracht. ARP ist das, was anhand einer IP-Adresse die MAC-Adresse eines benachbarten Knotens ermittelt, und mit dem Befehl arp -a lässt sich die vom PC gespeicherte Zuordnungstabelle einsehen.
Auf Hardware-Ebene ist es der Switch (Switching-Hub), der anhand von L2 weiterleitet. Ein Switch wählt den Ausgangsport ausschließlich anhand der Ziel-MAC-Adresse und schaut sich die als Fracht mitgeführte IP-Adresse gar nicht erst an.
5. L3, die Vermittlungsschicht — Zustellung bis ans Ende der Welt
Die nächsten 20 Bytes sind der IPv4-Header. Hier die wichtigsten Felder im Überblick.
45 Version = 4, Header-Länge = 5 Worte (20 Bytes)
00 9d Gesamtlänge: 157 Bytes (IP-Header + TCP + HTTP; die 14 Bytes von Ethernet sind nicht enthalten)
40 06 TTL = 64, Protokoll = 6 (Fracht ist TCP)
3b 99 Header-Prüfsumme
c0 00 02 0a Quell-IP 192.0.2.10
c6 33 64 50 Ziel-IP 198.51.100.80
Die Aufgabe von L3 besteht darin, „bis zum endgültigen Ziel-Host zuzustellen, ganz gleich, wie viele Router dazwischenliegen“. Während L2 nur einen einzigen Abschnitt (einen Hop) transportiert, bleibt die Ziel-IP-Adresse von L3 vom Anfang bis zum Ende der Kommunikation unverändert. Ein Router betrachtet die Ziel-IP-Adresse eines empfangenen Pakets, entscheidet, „an welchen Router als Nächstes übergeben wird“, ersetzt den L2-Header und sendet das Paket weiter.
TTL (Time To Live) ist das Feld, das diese Bewegung „über Router hinweg“ sichtbar macht. Es wird bei jedem überquerten Router um 1 verringert, und ein Paket, dessen TTL 0 erreicht, wird verworfen, woraufhin ein Fehler an den Absender zurückgemeldet wird. tracert (der Windows-Befehl zur Routenermittlung) sendet bewusst Pakete mit TTL = 1, 2, 3 … und deckt so nach und nach die Router entlang des Weges auf. Jede einzelne Zeile in der Ausgabe von tracert ist also das reale Abbild eines „L3-Hops“.
6. L4, die Transportschicht — Welcher Prozess bekommt es
Die nächsten 20 Bytes sind der TCP-Header.
cb 84 Quellport 52100
00 50 Zielport 80
00 00 03 e8 Sequenznummer
00 00 07 d0 Bestätigungsnummer
50 18 Header-Länge = 5 Worte, Flags [PSH, ACK]
ff ff Fenstergröße
a3 05 Prüfsumme
Bis L3 ist das Paket beim Ziel-„Host (der Maschine)“ angekommen. Auf dieser Maschine kommunizieren aber möglicherweise ein Webserver, eine Datenbank und zahlreiche weitere Prozesse gleichzeitig. Eine der Aufgaben von L4 besteht darin, anhand der Portnummer zu entscheiden, „an welchen Prozess (welchen Socket) übergeben wird“. Zielport 80 ist eine Konvention — „die Nummer, auf der ein HTTP-Server lauscht“ — und das Betriebssystem schaut sich diese Nummer an und legt die Daten im Empfangspuffer des entsprechenden Prozesses ab.
Die andere große Aufgabe von TCP ist es, über Sequenznummern, Bestätigungen, Neuübertragung und Flusskontrolle einen „zuverlässigen Byte-Strom“ bereitzustellen.4 Dieses Verhalten und der Umgang damit sind jeweils tief genug für einen eigenen Artikel, weshalb ich hier auf den Artikel zu TCP-Nachrichtengrenzen und den Artikel zu TCP-Neuübertragungen verweise. Nehmen Sie an dieser Stelle einfach das Gefühl mit: „Oberhalb von L4 sieht nichts mehr wie ein Netzwerk aus — es wirkt wie eine Pipe, die einen Prozess direkt mit einem anderen verbindet.“
Eine interessante Tatsache zeigt die Kluft zwischen dem Ideal des Modells und der Realität. Die TCP-Prüfsumme wird nicht allein über das TCP-Segment berechnet, sondern ist so definiert, dass ihr ein „Pseudo-Header“ mit L3-Informationen (Quell- und Ziel-IP-Adresse) vorangestellt wird.4 Wären die Schichten sauber voneinander unabhängig, dürften L3-Adressen eigentlich nicht in eine L4-Berechnung einfließen. Ein gutes Beispiel dafür, dass das OSI-Modell letztlich nur eine Landkarte zur Orientierung ist, während reale Protokolle Schichtgrenzen überschreiten, wo es zweckmäßig ist.
7. L5 und L6 — Wo Modell und Realität auseinanderklaffen
In unserer Zerlegungsdarstellung fehlten L5 (die Sitzungsschicht) und L6 (die Darstellungsschicht). Das ist der Hauptgrund dafür, dass sich viele mit OSI schwertun, deshalb sei es hier klar gesagt.
L5 und L6 existieren im realen TCP/IP-Stack nicht als eigenständige Schichten. Im Internetmodell von RFC 1122 ist alles oberhalb von TCP schlicht „Anwendungsschicht“.2 Die vom OSI-Modell vorgesehenen Rollen sind in der Realität wie folgt verstreut und andernorts aufgegangen.
| Was OSI vorsah | Beispiele, wo es real aufgegangen ist |
|---|---|
| L5: Aufbau und Verwaltung eines Dialogs (einer Sitzung) | TLS-Sitzung/-Handshake, HTTP-Cookies/-Tokens, anwendungseigene Login-Verwaltung |
| L6: Umwandlung und Verschlüsselung der Datendarstellung | TLS-Verschlüsselung, Zeichenkodierung (UTF-8), Serialisierungsformate wie JSON |
Bei HTTPS zum Beispiel wird TLS oberhalb von TCP (L4) eingeschoben, und HTTP fließt darin. „Zu welcher Schicht gehört TLS?“ ist die Art Frage, die man gerne zur Prüfungsfrage machen möchte, aber es hat keinen praktischen Wert, sich auf eine einzige richtige Antwort festzulegen. Wichtiger als sofort „L6“ antworten zu können ist, erklären zu können, dass TLS oberhalb von L4 und unterhalb von L7 liegt und sowohl Sitzungsverwaltung (eine L5-artige Rolle) als auch Verschlüsselung (eine L6-artige Rolle) übernimmt.
Im .NET-Code zeigt sich dieser Zusammenhang direkt darin, wie die Klassen ineinander verschachtelt werden. Umhüllt man den über TcpClient.GetStream() erhaltenen L4-Stream mit SslStream, wird der mit Write geschriebene Klartext zu TLS-Records verschlüsselt, bevor er überhaupt bei TCP ankommt.5
using var client = new TcpClient("example.com", 443);
// Den L4-Byte-Stream mit TLS (entspricht etwa L5/L6) umhüllen
using var ssl = new SslStream(client.GetStream());
await ssl.AuthenticateAsClientAsync("example.com");
// Hier wird der Klartext von L7 (HTTP) geschrieben. Die Verschlüsselung übernimmt SslStream
await ssl.WriteAsync(Encoding.ASCII.GetBytes("GET / HTTP/1.1\r\n..."));
Dieses Muster, einen Stream mit einem Stream zu umhüllen, ist die Code-Entsprechung der Kapselung. Betrachtet man in Wireshark die Kommunikation auf Port 443, erscheint die TCP-Nutzlast nur noch als undurchsichtiger Block namens Application Data — ein Beleg aus der Gegenrichtung dafür, dass „L7 in eine L6-artige Hülle verpackt wurde“.
8. Welche Schicht berührt Ihr C#-Code eigentlich?
Ordnen wir das bisher Gesagte den Werkzeugen zu, die ein Windows-App-Entwickler tatsächlich verwendet.
| Schicht | Reales Beispiel | Beispiel .NET-API | Wer fügt den Header hinzu |
|---|---|---|---|
| L7 Anwendung | HTTP, gRPC, eigenes Protokoll | HttpClient, Grpc.Net.Client, selbst gebautes Nachrichtenformat |
Ihr Code / eine Bibliothek |
| (entspricht etwa L5/L6) | TLS, Serialisierung, Zeichenkodierung | SslStream, JsonSerializer, Encoding |
Eine Bibliothek |
| L4 Transport | TCP, UDP | Socket, TcpClient, UdpClient (Header-Erzeugung durch das Betriebssystem) |
Der Protokoll-Stack des Betriebssystems |
| L3 Vermittlung | IP, Routing, ICMP | Ping, NetworkInterface (nur lesend) |
Der Protokoll-Stack des Betriebssystems |
| L2 Sicherung | Ethernet, Wi-Fi, ARP | (von einer gewöhnlichen App normalerweise nicht direkt berührt) | NIC-Treiber / NIC |
| L1 Bitübertragung | Elektrisches Signal, Licht, Funkwellen | – | NIC / Kabel / Luftschnittstelle |
Aus dieser Tabelle lassen sich zwei Dinge ablesen.
Erstens ist die Wahl der API eine Entscheidung darüber, „welche Schicht und alles darunter man abgibt“. Mit HttpClient können Sie sogar den Aufbau von L7 delegieren; mit Socket müssen Sie L7 komplett selbst schreiben. Umgekehrt greift eine gewöhnliche Windows-App so gut wie nie direkt auf L3 oder darunter zu (Raw Sockets erfordern Administratorrechte und unterliegen starken Einschränkungen).
Zweitens übergeben Sie an Socket.Send „nur“ die Byte-Folge von L7 — nichts weiter. Teil 2 des Beispiels ist eine Demo, die tatsächlich eine HTTP-Anfrage über Loopback sendet; die Anwendung stellt dabei lediglich 60 Bytes HTTP-Text bereit, während die in Kapitel 3 gesehenen 54 Bytes an Headern von Betriebssystem und NIC hinzugefügt werden. Der Netzwerkcode Ihrer App erledigt in Wirklichkeit nur die Aufgabe, die innerste Fracht von sieben Schichten zu erzeugen — das ist die genaue Position Ihres Codes im OSI-Modell.
using var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await socket.ConnectAsync(IPAddress.Loopback, port);
byte[] request = Encoding.ASCII.GetBytes(
$"GET / HTTP/1.1\r\nHost: localhost:{port}\r\nConnection: close\r\n\r\n");
// Übergeben wird nur die Byte-Folge von L7. Die TCP/IP/Ethernet-Header
// werden jenseits dieses Aufrufs (von OS und NIC) hinzugefügt
int sent = await socket.SendAsync(request);
9. Selbst ausprobieren — einen Frame zusammenbauen und in Wireshark öffnen
Damit aus „gelesen und verstanden“ ein „gesehen und verstanden“ wird, zeige ich Ihnen, wie Sie den Beispielcode ausführen.
Im Zentrum des Beispiels steht SampleFrameBuilder, der den Frame aus Kapitel 3 exakt in der Reihenfolge zusammenbaut, in der er von L7 nach L2 umhüllt wird. Was beim Senden auf jeder Schicht passiert, spiegelt sich direkt in der Reihenfolge der Methoden wider.
public static byte[] BuildHttpGetFrame()
{
// L7: Die Anwendung übergibt an Send „nur“ diese Byte-Folge
byte[] http = Encoding.ASCII.GetBytes(HttpRequest);
// L4: Der Protokoll-Stack des Betriebssystems stellt den TCP-Header voran
byte[] tcp = WrapInTcp(http);
// L3: Zusätzlich wird der IPv4-Header vorangestellt
byte[] ip = WrapInIpv4(tcp);
// L2: Kurz vor dem NIC-Treiber wird der Ethernet-Header vorangestellt
return WrapInEthernet(ip);
}
Führt man die Demo aus, wird zusätzlich zur Anzeige von Hexdump und verschachtelter Ansicht dieser Frame als pcap-Datei geschrieben.
dotnet run --project samples/Demo
Öffnen Sie die erzeugte Datei sample-http-get.pcap in Wireshark.6 Im mittleren Bereich erscheinen vier Zeilen untereinander — Ethernet II / Internet Protocol Version 4 / Transmission Control Protocol / Hypertext Transfer Protocol — und klickt man eine davon an, wird im Hexdump darunter genau der zugehörige Byte-Bereich hervorgehoben. Ein Industriestandard-Tool zeigt Ihnen also genau dasselbe wie die verschachtelte Ansicht aus Kapitel 3. Sobald Sie das bestätigt haben, geht es weiter mit echtem Datenverkehr: Starten Sie eine Aufzeichnung in Wireshark, setzen Sie den Filter etwa auf tcp.port == 443, öffnen Sie im Browser irgendeine Website, und Sie können bestätigen, dass jede echte Kommunikation aus genau dieser Verschachtelung besteht.
Auch in der Implementierung des Zerlegers (PacketDissector) steckt eine praxisrelevante Lektion. Beim Herausschneiden der IPv4-Fracht muss man sich zum Beispiel auf das TotalLength-Feld des Headers verlassen, statt einfach den gesamten Rest des Empfangspuffers zu nehmen. Der Grund: Ethernet hat eine Mindest-Frame-Länge (60 Bytes), und an kurze Pakete wird am Ende bedeutungsloses Padding angehängt. „Ein Anliegen der äußeren Schicht (Padding) mithilfe der Längenangabe der inneren Schicht entfernen“ — auch das ist ein Beispiel dafür, wie sich die Aufteilung der Verantwortung zwischen den Schichten in der Implementierung niederschlägt, und es wird über einen Unit-Test abgesichert.
10. Das OSI-Modell in der Praxis nutzen — Eingrenzung mit dem Vokabular der Schichten
Eingangs habe ich geschrieben, dass „OSI als Vokabular überlebt hat“. Hier sind zwei konkrete Situationen, in denen sich dieses Vokabular tatsächlich bewährt.
Fehlersuche. Übersetzt man eine Meldung wie „ich komme nicht zum Server durch“ in das Vokabular der Schichten, lässt sie sich systematisch eingrenzen. Der Standardansatz ist, von unten nach oben zu prüfen.
| Prüfung | Verwendetes Mittel | Schicht, deren Funktionsfähigkeit bestätigt wird |
|---|---|---|
| Verbindungsanzeige / Wi-Fi-Status | Sichtprüfung | L1–L2 |
| Ping zum Gateway im selben Segment | ping 192.168.x.1 |
L3 in der eigenen Umgebung |
| Ping zum Ziel-Host | ping <Ziel> |
L3 entlang des gesamten Pfads |
| TCP-Verbindung zum Zielport | Test-NetConnection <Ziel> -Port 443 |
L4 (plus etwaige Firewall unterwegs) |
| HTTP-Anfrage senden | curl -v oder die Anwendung selbst |
L7 (plus TLS) |
Wenn zum Beispiel „der Ping durchgeht, aber Test-NetConnection fehlschlägt“, ist alles bis L3 in Ordnung, und der Verdacht verengt sich auf etwas, das den L4-Port blockiert (ein gestoppter Dienst, eine Firewall, eine falsch konfigurierte Portnummer). Wenn „die TCP-Verbindung zustande kommt, HTTP aber 400 zurückliefert“, liegt das Problem nicht am Netzwerk, sondern an L7 (dem Inhalt der Anfrage). Statt wahllos Kabel zu ziehen und wieder einzustecken, Schicht für Schicht feststellen, bis wohin noch alles funktioniert — so wird das OSI-Modell in der Praxis eingesetzt.
Gemeinsame Sprache für Gespräche. Formulierungen wie „das sieht nach einem L2-Problem aus, könntest du dir den Switch-Port ansehen“ oder „das ist eine L7-Sache, das geht ans App-Team“ funktionieren präzise zwischen Netzwerkverantwortlichen, Infrastruktur-Teams und App-Entwicklern. Die Schichtnummer ist ein branchenweit geteiltes Koordinatensystem, um einen Verantwortungsbereich knapp zu benennen.
11. Verbreitete Missverständnisse richtigstellen
Zum Schluss stellen wir häufig anzutreffende Missverständnisse rund um das OSI-Modell richtig.
- „Das Internet läuft auf den sieben Schichten von OSI.“ — Tut es nicht. Implementiert ist TCP/IP (effektiv vier Schichten); OSI ist ein Referenzmodell für Erklärung und Gespräche.2
- „Die vier Schichten von TCP/IP entsprechen sauber den sieben Schichten von OSI.“ — Die Zuordnung von L5 bis L7 ist von Natur aus unscharf. Man sieht oft Tabellen mit „TCP/IP-Anwendungsschicht = OSI L5 + L6 + L7“, aber wie in Kapitel 7 gezeigt, sind die Rollen von L5 und L6 in der Realität auf TLS und Serialisierungsformate verstreut.
- „TLS ist ein Protokoll der Schicht 6 (oder Schicht 5).“ — Es hat keinen Sinn, es auf eine einzige Schicht festzulegen. Die zutreffende Beschreibung lautet: Es liegt oberhalb von L4, unterhalb von L7, und kombiniert Rollen, die L5 und L6 entsprechen.
- „Am Portnummer erkennt man das Protokoll.“ — Port 80 bedeutet nicht zwingend HTTP. Eine Portnummer ist eine Konvention; was tatsächlich fließt, weiß man erst, wenn man sich die Nutzlast ansieht. Deshalb erkennt der Zerleger im Beispiel HTTP nicht anhand der Portnummer, sondern anhand der führenden Zeichen des Inhalts.
- „Switches sind L2-, Router sind L3-Geräte.“ — Als Ausgangspunkt ist das richtig, aber in der Realität gibt es ganz normal Geräte, die mehrere Schichten überspannen: L3-Switches, Load Balancer, die auf L4-Basis verteilen, oder WAFs, die L7 inspizieren. Genauer erfasst man das mit der Frage: „Bis zu welcher Schicht liest dieses Gerät eigentlich?“
12. Zusammenfassung
- Das OSI-Modell ist keine Implementierung, sondern ein Vokabular, um in Schichten zu denken. In der Realität läuft TCP/IP (effektiv vier Schichten)
- Die sieben Schichten sind kein konzeptionelles Diagramm, sondern physisch in der Byte-Folge eines einzelnen Frames verschachtelt (L2: 0–13, L3: 14–33, L4: 34–53, L7: ab 54)
- Jede Schicht liest nur ihren eigenen Header und kümmert sich nicht um die Fracht (die inneren Schichten) — das ist Kapselung
- L5 und L6 existieren im realen Stack nicht eigenständig; TLS und Kodierung haben ihre Rollen übernommen
- Ihr C#-Code schreibt nur die Byte-Folge von L7. Die TCP/IP-Header fügt das Betriebssystem hinzu, Ethernet die NIC
- In der Praxis nützlich ist es zur Fehlersuche, indem man Schicht für Schicht von unten nach oben die Funktionsfähigkeit prüft, sowie als gemeinsame Sprache zwischen Teams
- Baut man mit dem Beispielcode einen Frame zusammen und öffnet ihn in Wireshark, lässt sich alles in diesem Artikel mit eigenen Augen nachvollziehen
Verwandte Artikel
- Das Missverständnis, dass man über TCP in denselben Einheiten empfangen kann, in denen man gesendet hat — Empfangsdesign für den Umgang mit einem Byte-Strom
- Ursache und Eingrenzung von Kommunikationsabbrüchen bei Industriekameras durch TCP-Neuübertragungen
- Praktische C# async/await-Entscheidungstabelle — Task.Run und ConfigureAwait
Verwandte Beratungsbereiche
Die KomuraSoft LLC (合同会社小村ソフト) übernimmt das Design und die Implementierung von Windows-Anwendungen, die über TCP/IP kommunizieren, die Ursachenanalyse bei Kommunikationsproblemen mit Industriegeräten (“bricht gelegentlich ab”, “wird langsamer”) sowie die Unterstützung bei der Fehlersuche mithilfe von Paketmitschnitten.
- Windows-Anwendungsentwicklung
- Fehleranalyse und Ursachenermittlung
- Technische Beratung und Design-Review
- Kontakt
Referenzen
-
ITU-T, X.200 : Information technology - Open Systems Interconnection - Basic Reference Model: The basic model. Die Originalquelle des OSI-Basisreferenzmodells (inhaltsgleich mit ISO/IEC 7498-1). Zur Definition jeder der sieben Schichten. ↩ ↩2
-
IETF, RFC 1122 - Requirements for Internet Hosts – Communication Layers. Die RFC, die die von Internet-Hosts zu implementierenden Anforderungen festlegt. Zur Gliederung der Protokollsuite in vier Schichten: Verbindungsschicht, IP-Schicht, Transportschicht und Anwendungsschicht. ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Socket Class (System.Net.Sockets). Die Socket-API in .NET. Dazu, dass die Anwendung die Nutzlast übergibt und die Erzeugung der Protokoll-Header vom Protokoll-Stack des Betriebssystems übernommen wird. ↩
-
IETF, RFC 9293 - Transmission Control Protocol (TCP). Die aktuelle TCP-Spezifikation. Zur Bereitstellung von Zuverlässigkeit durch Sequenznummern und Bestätigungen sowie zur Verwendung eines Pseudo-Headers mit IP-Adressen bei der Prüfsummenberechnung. ↩ ↩2
-
Microsoft Learn, SslStream Class (System.Net.Security). Zur Klasse, die einen bestehenden Stream (in der Regel TCPs
NetworkStream) umhüllt und Verschlüsselung sowie Authentifizierung über TLS bereitstellt. ↩ -
Wireshark Foundation, Wireshark User’s Guide. Zum Öffnen von Aufzeichnungsdateien, zur zusammenhängenden Anzeige von Paketdetail- und Byte-Folge-Pane sowie zur Verwendung von Anzeigefiltern. ↩
Verwandte Artikel
Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.
Infobereich-Symbole und Toast-Benachrichtigungen in Windows-Apps — Fallstricke von NotifyIcon und die richtige AppNotification-Wahl
Ein praktischer Leitfaden dafür, eine geschäftliche Windows-Anwendung im Infobereich (System Tray) resident zu halten und den Benutzer üb...
Wie lange laufen VB6-Anwendungen noch? — Support-Status der Laufzeitumgebung und ein praxisnaher Weg zur .NET-Migration
Wie lange laufen VB6-Anwendungen noch? Dieser Artikel ordnet die Asymmetrie zwischen der Support-Richtlinie für die VB6-Laufzeitumgebung ...
Japanische Ära, Feiertage und Abrechnungsstichtage in Business-Apps — Übergangsresistentes Design, JapaneseCalendar und Werktagsberechnung in der Praxis
Auf einem Beleg muss „Reiwa 8“ stehen, die Werktagsberechnung muss Feiertage ausschließen, die Zahlung ist am letzten Werktag des Folgemo...
Wie man die Windows-Sitzungsisolierung versteht — Session 0, RDP und die gleichzeitige Nutzung durch mehrere Benutzer
Dieser Artikel erklärt das Konzept der Windows-„Sitzung“ (Session), das Windows-App-Entwickler immer wieder verwirrt. Er behandelt, warum...
Mehrsprachigkeit für WinForms/WPF-Anwendungen ── resx, Satelliten-Assemblies und Kulturumschaltung in der Praxis
Dieser Artikel behandelt die Mehrsprachigkeit von Windows-Desktopanwendungen aus Praxissicht: den Unterschied zwischen CurrentCulture und...
Verwandte Themen
Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.
Technische Windows-Themen
Portal zu Windows-Entwicklung, Fehleranalyse und der Nutzung bestehender Assets.
Fehleranalyse und Langzeitprobleme
Sporadische Fehler, Kommunikationsdiagnose, Langzeitabstürze und Tests von Fehlerpfaden.
Leistungen zu diesem Thema
Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.
Windows-App-Entwicklung
Geschäftsanwendungen, Geräteintegration und Kommunikationstools von den Anforderungen bis zur Umsetzung.
Häufige Fragen
Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.
- Werden die sieben Schichten des OSI-Modells im realen Internet tatsächlich verwendet?
- Nein. Was im realen Internet tatsächlich läuft, ist die TCP/IP-Protokollsuite (effektiv vier Schichten); die eigentlichen 7-Schichten-Protokolle von OSI verloren in den 1990er-Jahren das Rennen um die Verbreitung und wurden am Ende kaum genutzt. RFC 1122, das die Grundlage des Internets legte, erklärt die Welt anhand von vier Schichten: der Verbindungsschicht, der IP-Schicht, der Transportschicht und der Anwendungsschicht. Überlebt hat das Modell als gemeinsames Vokabular für Fehlersuche und Gespräche — Formulierungen wie „lass uns das auf L2 eingrenzen“ oder „das ist ein L7-Problem“.
- Wo existieren die Sitzungsschicht (L5) und die Darstellungsschicht (L6) eigentlich wirklich?
- Sie existieren im realen TCP/IP-Stack nicht als eigenständige Schichten. Die vom OSI-Modell vorgesehenen Rollen sind in der Praxis verstreut und anderswo aufgegangen: L5 (Aufbau und Verwaltung eines Dialogs) entspricht dem TLS-Handshake oder HTTP-Cookies und -Tokens, und L6 (Umwandlung und Verschlüsselung der Datendarstellung) entspricht der TLS-Verschlüsselung, der Zeichenkodierung und Serialisierungsformaten wie JSON. Es hat keinen praktischen Wert, TLS auf eine einzige Schicht festzulegen — wichtiger ist, erklären zu können, dass es oberhalb von L4 und unterhalb von L7 liegt und Rollen kombiniert, die L5 und L6 entsprechen.
- Wenn es schon eine IP-Adresse gibt, wozu braucht man dann noch eine MAC-Adresse?
- Weil die Schichten die Verantwortung unterschiedlich aufteilen. Die IP-Adresse (L3) ist die Adresse, die auf das endgültige Ziel zeigt, und sie ändert sich vom Anfang bis zum Ende der Kommunikation nicht. Die MAC-Adresse (L2) ist die Kennzeichnung dessen, der den nächsten einzelnen Abschnitt transportiert, und sie wird bei jedem Überqueren eines Routers ausgetauscht. Ein Frame, der von einem Büro-PC an einen Webserver gesendet wird, hat als Ziel-MAC-Adresse nicht den Webserver, sondern das Standardgateway (den Router). ARP ist das, was die MAC-Adresse eines benachbarten Knotens anhand einer IP-Adresse ermittelt, und die Zuordnungstabelle lässt sich mit dem Befehl arp -a einsehen.
- Wofür ist das OSI-Modell in der Praxis wirklich nützlich?
- Für die Fehlersuche und die Kommunikation zwischen Teams. Eine Meldung wie „kann keine Verbindung zum Server herstellen“ lässt sich systematisch eingrenzen, indem man Schicht für Schicht von unten nach oben prüft, was noch funktioniert: Sichtprüfung der Verbindungsanzeige (L1-L2), Ping zum Gateway (L3), Bestätigung einer TCP-Verbindung zum Zielport (L4) und Senden einer HTTP-Anfrage (L7). Wenn beispielsweise der Ping durchgeht, die TCP-Verbindung aber fehlschlägt, verengt sich der Verdacht auf etwas, das den L4-Port blockiert, etwa einen gestoppten Dienst oder eine Firewall. Es dient außerdem als branchenweit geteiltes Koordinatensystem, um einen Verantwortungsbereich knapp zu benennen, wie in „das klingt nach einem L2-Problem, kannst du bitte den Switch prüfen“.
Autorenprofil
Profilseite des Artikelautors.
Go Komura
Geschäftsführer von KomuraSoft LLC
Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.
Öffentliche Links