Christian Seiler: TCP/IP-Kommunikation: Grundlagen

Beitrag lesen

Hallo Tom,

Ein xbeliebiger Client sendet über die ihm zur Zeit zugeordnete IP einen Request an den Server auf dessen Port 80. Der Server habe bitte hier eine feste IP, obwohl da auch anderes denkbar wäre.

Soweit richtig...

Beim Client wird pro Browserfenster ein Port geöffnet.

...das hier ist allerdings falsch. Und nachdem Du in Deinem restlichen Posting auch eine ganze Menge Dinge vermischt, die erst einmal gar nichts miteinander zu tun haben, möchte ich hier noch einmal ein paar Grundlagen von TCP/IP erläutern. Nicht, weil Dein Posting komplett falsch wäre, sondern weil da so viel richtiges mit falschem vermischt ist.

Zuerst muss man klar "IP" und "TCP" trennen. IP ist ein Protokoll, das dafür sorgt, dass die Pakete, die geschickt werden, zum richtigen Zielcomputer gelangen. Dazu besitzten alle Computer, die mit IP miteinander kommunizieren wollen, eine sogenannte IP-Adresse. Ich lasse im folgenden Mal "Sonderfälle" wie NAT-Router außen vor, da sie zum eigentlichen Verständnis dessen, was ich hier erklären will, nicht sonderlich viel beitragen (wenn auch "Sonderfall" bei der heutigen Verbreitung von NAT wohl etwas daneben ist ;-)). Stelle Dir nun vor, Du hast zwei Rechner A und B, die gerne auch an anderen Enden der Welt stehen können, solange es zwischen ihnen irgend eine Verbindung durchs Internet gibt (es müsste übrigens nicht das Internet sein, aber ich beschränke mich mal auch hier auf den Normalfall). Wenn nun Rechner A an Rechner B ein Paket schicken will, dann muss er einfach ein IP-Paket erzeugen, das vor allem 2 Informationen enthält: Als Ausgangsadresse ("Source IP address") muss er seine eigene hineinschreiben, als Zieladresse ("Destination IP address") die IP-Adresse des Rechners B. Bis auf ein paar Details zum Protokoll selbst, ist alles andere erst einmal irrelevant: Das Paket wird (sofern es nicht verloren geht) von der Internet-Infrastruktur automatisch an Rechner B weitergeleitet. Genauso kann Rechner B umgkehrt ein Paket mit seiner eigenen Adresse als Ausgangsadresse und der Adresse von Rechner A als Zieladresse an den Rechner A weitergeleitet.

Das ist es, was IP leistet. Was in dem Paket konkret enthalten ist, ist IP egal. Wenn man nun ausschließlich IP zur Kommunikation nutzen würde, hätte man Probleme, die Pakete sinnvoll zuzuordnen. Daher gibt es weitere Protokolle, die auf IP aufsetzen, die dann die tatsächlichen Daten enthalten. Diese weiteren Protokolle sind u.a. ICMP, IGMP, UDP, TCP, SCTP usw. usf. Praktisch relevant sind vor allem ICMP (Kontroll- und Statusnachrichten wie z.B. »ping«), UDP (einfache, verbindungslose Pakete) und TCP (2-Wege-Verbindungen). Jedes IP-Paket enthält zusätzlich zu Ausgangs- und Zieladresse nämlich noch ein Feld "Aufbauendes Protokoll", in dem angegeben wird, was für ein zusätzliches Protokoll verwendet wird.

Was hat es nun mit Ports auf sich? Ganz wichtig: Ein Port ist ein Konzept, das in TCP (und auch UDP, aber das ignoriere ich jetzt mal) vorhanden ist - ICMP zum Beispiel kennt keine Ports! Ein Port hat also NICHTS damit zu tun, ob ein Paket den Weg zum Zielrechner findet, oder nicht (von Filtern wie Firewalls mal abgesehen), denn das erledigt ja, wie bereits oben erwähnt, IP. Alles, was man erst einmal über Ports wissen sollte, ist, dass sie eine Nummer sind, bei TCP/IP zwischen 0 und 65535.

Was macht nun TCP? Zwei Dinge: Erstens sorgt es dafür, dass Verbindungen zwischen zwei Rechnern aufgebaut werden können, d.h. ein eindeutig identifizierter Datenkanal, zwischen dem Programme auf beiden Rechnern Daten austauschen können (ein Programm auf Rechner A könnte dann zum Beispiel "Hallo" schreiben und ein anderes Programm auf Rechner B mit "Welt" antworten). Wodurch wird dieser Datenkanal nun eindeutig identifiziert? Durch 4 Angaben: Ausgangsadresse, Ausgangsport, Zieladresse und Zielport. (Es gibt dann noch weitere Angaben, die dazu dienen, dass es nicht ganz so einfach ist, in eine bestehende Verbindung einzudringen, die sind aber für den reinen Transport irrelevant.) Mit den vier Angaben kann jeder der beiden beteiligten Rechner Pakete zu TCP-Verbindungen eindeutig zuordnen.

TCP macht noch ein paar mehr Dinge, zum Beispiel kümmert es sich darum, dass verloren gegangene Pakete erneut geschickt werden und es kümmert sich um so Dinge wie Fragmentierung (zusammen mit ICMP), das ist aber für die folgende Erklärung irrelevant.

Wie kommunizieren nun Programme über TCP/IP? Dazu gibt es auf allen mir bekannten Betriebsystemen das Konzept der "Sockets" (wenn auch einige Betriebsysteme das etwas anders umsetzen, als andere, das Grundprinzip bleibt das gleiche): Eine Socket ist (allgemein gesprochen) ein Objekt, für das das jeweilige Betriebsystem vorrangig zwei Funktionen zur Verfügung stellt: "Lese aus dem Socket" und "Schreibe ins Socket". Nehmen wir nun erst einmal den Fall an, dass die Verbindung bereits aufgebaut ist: Dann führt ein Befehl "Schreibe ins Socket" von einem Programm dazu, dass der Betriebsystemkern ein oder mehrere TCP/IP-Pakete generiert, die dann an den Zielrechner gesendet werden, automatisch mit den korrekten Ports gesetzt. Genauso wird jedes ankommende TCP/IP-Paket in einem Puffer gespeichert und wenn ein Programm nun den Aufruf "Lese aus dem Socket" tätigt, wird der Inhalt des Puffers zurückgegeben, d.h. das Programm kann die Nachricht der Gegenseite auslesen. Der Betriebsystemkern besitzt also Intern eine Zuordnung Socket <-> (Quadruplet von Ausgangs- und Zieladressen und -ports), die ist aber für das Programm, das kommuniziert, erstmal irrelevant (es sieht nur das Socket, außer es will explizit mehr sehen).

Wie wird nun eine Verbindung aufgebaut? Das Betriebsystem stellt (stark vereinfacht gesagt) eine Funktion "Verbinde mit (IP, Port)" zur Verfügung. Das Programm ruft die auf und erhält dann einen Socket zurück, das mit der offenen TCP-Verbindung mit der Gegenseite verknüpft ist - oder eine Fehlermeldung, falls etwas nicht geklappt hat. Was ist nun der Ausgangsport und die Ausgangsadresse der Verbindung? Das Betriebsystem weiß in der Regel, welche Adresse es zu verwenden hat, um eine Verbindung zu dem und dem Ziel durchzuführen und der Ausgangsport wird beliebig gewählt. Das heißt: Beim Aufbau einer Verbindung kann einem Programm der EIGENE Port, der dann genommen wird, egal sein, das übernimmt das Betriebsystem für einen, das ist dem Programm vollkommen egal - es will ja nur eine Verbindung (es KANN allerdings auch dem Betriebsystem mitteilen, welche Wünshe es für den Ausgangsport hat, aber Browser machen sowas definitiv nicht).

Und es stimmt auch nicht, dass hierbei ein Port "aufgemacht" wird - "offen" bezeichnet bei einem Port den Zustand, dass hinter dem Port eine Anwendung auf eingehende Verbindungen wartet (s.u.) - beim Verbindungsaufbau wird jedoch AUSSCHLIESSLICH ein zufälliger Ausgangsport ins erste TCP/IP-Paket hineingeschrieben und wenn dann eine Antwort von dem RICHTIGEN Rechner kommt, wird diese zugeordnet und der Anwendung zur Verfügung gestellt, alle anderen Pakete an den Port werden entweder ignoriert oder mit Fehler-Paketen ("Sorry, Du hast Dich verwählt") beantwortet.

Was machen nun Server, um einen Port "öffnen" zu können, damit Anfragen von beliebigen Clients beantwortet werden können? Sie sagen dem Betriebsystem, sie möchten ein Socket erstellen, damit aber keine Verbindung aufbauen, sondern diese auf dem und dem Port entgegen nehmen. Damit erhalten sie dann das "Haupt-Socket". Jedes Mal, wenn nun ein Client eine Verbindung aufgebaut hat, wird ein "Unter-Socket" erstellt, über das das Serverprogramm dann mit dem konkreten Client kommunizieren kann. Um mal ein Beispiel zu machen: Ein Webserver öffnet Port 80, indem es so ein "Haupt-Socket" erstellt. Dann kommt eine eingehende Verbindung von Client A herein. Hier wird nun ein "Untersocket" erstellt, das mit der konkreten Verbindung zwischen Client A und dem Server verknüpft ist. Kommt jetzt nun auch noch eine Verbindung von Client B herein, wird ein weiteres "Untersocket" erstellt, das mit der anderen Verbindung verknüpft ist. Auf welche Weise das Serverprogramm nun Verbindungen abarbeitet, ist ihm überlassen - es könnte die zum Beipsiel einfach eine nach der anderen verarbeiten (wird allerdings in der Praxis aus Performancegründen meist anders gemacht ;-)). Die heißen übrigens nicht wirklich "Haupt-" und "Untersocket", mir fiel nur kein besserer Term ein, das zu Veranschaulichen.

Noch kurz ein paar Worte zu HTTP: Die einfachste Vorstellung von HTTP, die man haben kann, ist folgende: HTTP setzt auf TCP/IP auf, der Standardport ist 80. Was passiert nun, wenn ein Browser eine Resource abrufen will? 1. Er baut eine TCP/IP-Verbindung zum Zielwebserver auf (meist Port 80). 2. Er schickt dem Server einen Anfrage ("Request"). 3. Er erhält vom Webserver eine Antwort ("Response"). 4. Der Webserver schließt nach der Anfrage die Verbindung, der Client weiß, dass die Antwort zu Ende ist. Gut, seit HTTP/1.1 ist dank Keep-Alive und Pipelining das ganze noch viel komplizierter geworden (Keep-Alive bedeutet, dass eine Verbindung wiederverwendet werden kann), aber das Grundprinzip, dass JEDER Request bei HTTP isoliert ist, bleibt das gleiche und die obige Vorstellung ist sehr hilfreich für das Verständnis von HTTP - auch wenn es heutzutage in Wirklichkeit etwas anders abläuft.

Und ganz wichtig: Das hat NICHTS, aber auch GAR NICHTS mit Browserfenstern zu tun! Ob ein Browser pro Fenster (oder Tab oder was auch immer) mehrere Verbindungen gleichzeitig aufmacht, um zum Beispiel mehrere Bilder gleichzeitig zu laden oder ob er für ALLE Fenster insgesamt immer nur eine einzige Verbindung nach der anderen aufmacht, ist dem Programmierer des Browsers überlassen.

Was hat es nun mit mod_unique_id auf sich beim Apachen? Das Modul erzeugt für jeden Request eine hinreichend eindeutige ID, die dann Programme oder Scripte, die bei dem Request ausgeführt werden, für eigene Zwecke nutzen können. In der Doku zu mod_unique_id steht außerdem, dass:

| Unique identifiers are useful for various reasons which are beyond the
| scope of this document.

Sprich: Wofür ein Programm oder Script das dann einsetzt, bleibt dem Programmierer überlassen, diese Unique-ID ist lediglich eine Hilfestellung des Apachen, damit das Programm eine eindeutige ID erhält und sich nicht erst überlegen muss, wo es sich eine erzeugen kann. Wenn man das Modul deaktiviert, funktionieren Requests jedoch weiterhin und diese eindeutige ID wird schlichtweg nicht erzeugt.

---------------------------- schnipp ------------------------------------

[Sessions und Threads und so ein Zeug.]

Mir ist nach mehrmaligem Lesen endlich klar geworden, worauf Du hinaus willst mit Deinem Beispiel. Zum einen: Das hat mit Threads oder keinen Threads ABSOLUT nichts zu tun, genausowenig (wie Sven schon erzählt hat) mit der Abschottung von Requests zueinander innerhalb des Webservers (das kann der nämlich prima alleine, ohne deratige IDs und so einen Kram). Zum anderen: Ich halte Dein Beispiel definitiv nicht für den idealen Einsatzzweck für mod_unique_id - im Gegenteil, für Dein Szenario gibt es diverse andere Lösungsmöglichkeiten, die in meinen Augen viel sinnvoller sind (siehe z.B. Svens Antwort). Zudem führt Dein Szenario eben gerade weil Sessions Request-übergreifend sind und die Unique-ID, die vom Apache erzeugt wird, auf Request-Ebene generiert wird, zu sehr viel vollkommen unnötiger Verwirrung.

Viele Grüße,
Christian