zum Inhalt

1 Einleitung

1.1 Technisches

1.1.1 Verbindungsorientierte und verbindungslose Protokolle

Man unterscheidet in der Datenkommunikation zwischen zwei Arten von Protokollen, sogenannten verbindungsorientierten und verbindungslosen, d.h. Protokollen, die vor dem Austausch von Daten eine Verbindung zum Kommunikationspartner herstellen und solchen, bei denen nur einzelne Nachrichten versendet werden können. Ohne jetzt auf die Vor- oder Nachteile näher einzugehen (die von Fachleuten zum Teil mit religiösem Eifer diskutiert werden), unterscheiden sich die beiden in der Regel durch die Menge ihrer Sicherheitsfunktionen - und dies hat wiederum Auswirkungen auf die Effizienz. Ein verbindungsorientiertes Protokoll mit vielen Sicherheitsfunktionen hat meist einen höheren Verarbeitungsaufwand im Rechner als ein verbindungsloses Protokoll. In Tabelle 1.1 sind die Charakteristiken beider Typen zusammengefaßt.

Bezeichnung Funktionsweise Einsatzgebiet
verbindungsorientiert Drei Phasen:
Verbindungsaufbau,
Datentransfer,
Verbindungsabbau
Terminalsitzungen,
Datentransfer
verbindungslos Transport von in sich
abgeschlossenen Nachrichten, zustandslos
Verzeichnisdienste,
Datenbanken,
transaktionale Systeme
Tabelle 1.1: Protokolltypen [2] [2]

Der Ablauf des Nachrichtenaustauschs in einem verbindungsorientierten Protokoll ist vergleichbar mit einem Telefongespräch: Erst nach der gegenseitigen Vorstellung der Gesprächspartner und dem Austausch von bestimmten Formalismen beginnt der eigentliche Datenaustausch.

Die Verbindung wird erst dann wieder abgebrochen, nachdem sich beide Seiten überzeugt haben, daß Übereinstimmung im Verständnis der ausgetauschten Informationen herrscht. Deshalb sagt man auch, daß verbindungsorientierte Protokolle virtuelle Verbindungen (virtual circuits) herstellen. Virtuelle Verbindungen, die sich aus der Sicht eines UNIX-Programmierers wie eine bidirektionale Pipe verhalten, verwendet man dort, wo Kontext im Nachrichtenaustausch wichtig ist, über eine relativ lange Zeitdauer hinweg eine Verbindung aufrechterhalten werden soll oder Datenübertragungssicherheit eine Rolle spielt. Über eine physikalische (reale) Leitung können in der Regel mehrere virtuelle (logische) Verbindungen aufrechterhalten werden.

Informationseinheiten in verbindungslosen Protokollen sind vergleichbar mit Telegrammen, da sie in der Regel in sich abgeschlossene Nachrichten darstellen. Man nennt diese Informationseinheiten daher auch Datagramme. Verbindungslose Protokolle kommen in erster Linie im Transaktionsbereich, z.B. für Datenbankabfragen zum Einsatz. Da Sicherungsfunktionen wie Flußkontrolle oder Paketwiederholung mit der zustandslosen Natur verbindungsloser Protokolle unvereinbar sind, muß gegebenenfalls eine übergeordnete Schicht definiert werden, die entsprechende Mechanismen beinhaltet und so einen zuverlässigen Datentransfer gewährleistet. Beispiele für derartige Kombinationen sind TCP als übergeordnete Schicht von IP und RPC (Remote Procedure Call) auf der Basis von UDP.

In der Transportschicht der TCP/IP-Architektur existieren beide Arten von Protokollen: TCP (Transfer Control Protocol) als ein verbindungsorientiertes und UDP (User Datagram Protocol) als ein verbindungsloses Protokoll. IP (Internet Protocol) ist übrigens ein verbindungsloses Protokoll der Vermittlungsschicht.



1.1.2 Ports

Auf der Transportebene der oben vorgestellten Protokolle existieren zur Adressierung sogenannte Portnummern (übersetzt: Kanalnummern). Portnummern sind 16 Bits groß, entsprechend könnte ein Hostrechner bis zu 65535 verschiedene TCP-Verbindungen aufbauen.

Auch UDP verwendet zur Adressierung Portnummern, zu beachten ist aber, daß TCP und UDP jeweils eigene Adreßräume haben, d.h. Portnummer 511 in TCP ist nicht identisch mit Portnummer 511 in UDP! Der Gültigkeitsbereich einer Portnummer ist auf einen Host beschränkt. Netzwerknummer, Host-ID und Portnummer spezifizieren zusammen einen Kommunikationsendpunkt ähnlich einer Nebenstelle an einer Telefonanlage. Diese "Kommunikationsendpunkte" werden eben "Socket" genannt.

Ähnlich wie beim Telefon geht auch der Aufbau einer Verbindung über TCP vonstatten: auch hier gibt es einen passiven Partner, den Angerufenen, und einen aktiven Partner, den Anrufer. Bevor zwei Programme miteinander kommunizieren können, müssen beide Kommunikationsendpunkte eröffnen, deren Adressen in den Protokollköpfen der einzelnen Schichten verwendet werden. Damit sie allerdings zur Verbindungsaufnahme zusammenfinden, muß die Adresse des passiven Partners dem aktiven Partner bekannt sein, d.h. beide Seiten müssen vorher eine Portnummer vereinbart haben, unter der der passive Partner, auch Server genannt, auf den Verbindungsaufbau wartet. Die Portnummer des aktiven Partners, auch Client genannt, ist irrelevant, solange der Server keine spezielle Portnummer für den Client vorschreibt.

Wie im Telefonsystem die Störungsstelle oder Zeitansage, könnte man TCP/IP-Applikationen, wie z.B. Telnet oder FTP, als feste Dienstleistungen betrachten, die unter einer definierten, allgemein bekannten Nummer erreichbar sind. Eine derartige definierte Nummer wird in der TCP/IP-Welt als well-known port number bezeichnet. Man könnte daher sagen: Jeder Dienst (Service) muß eine eigene Portnummer festlegen. Über diese Portnummer adressiert der Kunde (Client) den Server, der den Dienst bereitstellt. In Tabelle 1.2 sind einige Dienste dieser Art mit Portnummer und Protokoll aufgeführt.

Bis zur Portnummer 1024 sind die Ports spezifiziert und von der Fa. SUN verwaltet. Nummern größer als 1024 stehen "zur freien Verfügung". Inzwischen ist die Zahl der Applikationen aber derart gewachsen, daß eine nähere Kontrolle der selbst verwendeten Portnummer nicht Schaden kann und Kollisionen mit oftgenutzten Programmen z.B. im Internet vermeiden hilft.

Dienst Portnummer Protokoll
echo 7 tcp/udp
daytime 13 tcp/udp
ftp-data 20 tcp
ftp 21 tcp
telnet 23 tcp
smtp 25 tcp
finger 79 tcp
http 80 tcp
portmap 111 tcp/udp
login 513 tcp
rwhod 513 udp
Xserver 6.000 tcp
Tabelle 1.2: Auszug aus der Liste der definierten Portnummern [2] [2]





1.2 Historie

1.2.1 Hintergrund

Mit 4.2BSD wurde 1981 in UNIX-Systemen [3] [3] zum ersten Mal eine ausschließlich für die Kommunikation zwischen Prozessen konzipierte Gruppe von Programmierschnittstellen eingeführt, die sogenannte Socket-Schnittstelle. Sockets waren damals revolutionär, da sie als generische Kommunikationsschnittstelle ausgelegt sind: neben TCP und UDP kann man über sie auch lokale Interprozeßkommunikation in der sogenannten UNIX-Domain durchführen. Außerdem erlaubten sie den direkten Zugriff auf die IP-Ebene.

Zunächst konnten über Sockets nur zwei unterschiedliche Kommunikationsbereiche (sprich Transportsysteme), nämlich Internet (TCP/IP) und UNIX, bedient werden. In 4.3BSD kamen die Protokolle des Xerox Network System (XNS) dazu. Viele Entwickler haben Anwendungen für die Socket-Schnittstelle entwickelt, so daß sie heute in allen TCP/IP-Implementierungen zu finden ist. Wichtige Technologien wie z.B. die ersten Versionen von NFS (Network File System, Fa. SUN), das X-Window-System (vom M.I.T.) oder DCE RPC von OSF setzen auf die Socket-Schnittstelle auf.

Socket-Schnittstellen sind zwar von keiner Institution genormt, stellen aber einen de-facto- bzw. Industriestandard dar - was zum einen daran liegen dürfte, daß sie leicht verständlich sind, zum anderen fügen sie sich ausgesprochen harmonisch in die UNIX-Umwelt ein. Eine Variante der Socket-Schnittstelle wurde von Microsoft und verschiedenen anderen Firmen unter der Bezeichnung WinSock in das Schnittstellenangebot der Windows Open Service Architecture (WOSA) aufgenommen und dürfte damit auch ein etablierter Standard in der PC-Welt sein.



1.2.2 Systemaufrufe

Eine der Hauptkriterien beim Entwurf der Socket-Schnittstellen war ihre nahtlose Integration in die bestehenden UNIX-Systemschnittstellen. Man kann sagen, daß dieses Kriterium erfüllt wurde, ohne dadurch die Flexibilität bei der Bedienung der unterschiedlichsten Netzwerkarchitekturen aufgegeben zu haben. Auffallend ist zunächst die Symmetrie der in Server- und Client- Programmen verwendeten Schnittstellen: bis auf einen gezwungenermaßen unterschiedlichen Teil beim Verbindungsaufbau durch den Client und der Verbindungsannahme durch den Server wird die gleiche Abfolge von Systemaufrufen durchgeführt.

Besonders vorteilhaft bei der Integration von TCP/IP in UNIX ist die Tatsache, daß TCP ähnlich wie UNIX-Pipes nicht satz- sondern datenstrom-orientiert arbeitet. Da die Systemaufrufe read und write in fast allen Fällen zur Ein- und Ausgabe unter TCP ausreichend sind, lassen sich bestehende Programme ohne große Probleme auch in vernetzter Umgebung weiter betreiben.

UDP-basierende Kommunikation unterscheidet sich etwas von dem in UNIX vorherrschenden Datenstrommodell, und obwohl sie sich theoretisch mit Standard-Systemaufrufen betreiben läßt, ist in der Regel die Verwendung der speziell dafür vorgesehenen Schnittstellen anzuraten. Man verwendet UDP daher in Einsatzfällen wie z.B. effizienten Abfragediensten, wenn Broadcast-Funktionen benötigt werden oder wenn oberhalb der UDP-Socket-Schnittstelle eine eigene anwendungsspezifische Schnittstelle existiert (z.B. RPC).





1.3 Berkeley-Sockets

Aus den Bemühungen heraus das 4.xBSD-Betriebssystem TCP/IP-fähig zu machen ist es zum Quasistandard bei der Implementierung von TCP/IP und der Socketprogrammierung geworden - sicherlich auch durch die Freigabe des kompletten Betriebbsystem-Quellcodes! Die meisten UNIX-„Derivate" benutzen immer noch diesen Code des BSD. Die Verwandschaft schlägt sich nieder in der Namensgebung für solche „speziellen" Sockets - eben Berkeley-Sockets - ein Tribut an die BSD-Entwickler von der Universität Berkeley.

Wie bereits weiter oben erwähnt, wurde diese erste Socketimplementierung bereits 1981 entwickelt. Die sechs Methoden open, create, close, read, write, lseek wurden damals implementiert. Bis dahin wurden diese nur für Datei-Ein- und Ausgabe benutzt. Netz-Ein- und Ausgaben umfassen jedoch mehr Details und Optionen wie Datei-E/A. Z.B. müssen folgende Punkte berücksichtigt werden:




Ein typisches "Berkeley-Sockets TCP-Szenario" ist im folgenden Bild dargestellt:

Schritt 1: Aufbau der Socket-Endpunkte

Schritt 2: Einrichten des Ports auf dem Server

Schritt 3: Server auf Verbindungsanforderung warten lassen (listen())

Schritt 4: Client mit Server verbinden (Anforderung schicken!)

Schritt 5: Server „akzeptiert" Verbindung

Schritt 6: Lese/Schreiboperationen

Schritt 7: Beenden der Verbindung und Schließen der Endpunkte
Abb. 1.1 Typisches TCP-Socket-Szenario [1] [1]





1.4 Stream-/Datagram-/Raw-Sockets

Entsprechend den verschiedenen Protokollen (TCP/UDP) war es notwendig die Socketimplementierungen anzupassen. In den vorhergehenden Kapiteln wurde nur ober- flächlich auf die jeweiligen Eigenschaften eingegangen. Hier werden die Unterschiede zwischen den verschiedenen Socket-Typen besser herausgestellt:





Zusamenfassung Kapitel 1:

Socket stellt eine Basis zur sicheren und kontinuierlichen Verbindung zwischen zwei "Kommunikationsobjekten" dar. Die beiden Objekte sind die Endpunkte der Verbindung, die solange aufrechterhalten wird, bis der Socket geschlossen wird. Eines der beiden Objekte ist normalerweise der Server, das andere der Client. Dabei wartet eine Server Applikation auf einem spezifizierten Port auf die Verbindungsanfrage eines Clients. Wenn dies geschieht, bauen beide eine eigene Verbindung auf, über die sie kommunizieren können. Während dieses Prozesses wird dem Client eine noch nicht benutzte Portnummer zugewiesen, welche dieser in seinen Socket einbindet. Nachrichten von Client zu Server werden durch das Schreiben in den Socket übermittelt und umgekehrt durch das Lesen aus diesem. Der Server wartet allerdings meist auf einem anderen Port auf weitere Anfragen - auch mit anderen Protokollen.

zu Kapitel 2 Kapitelanfang zum Inhalt