zum Inhalt

2 Java-Socket's

2.1 Überblick

Im Java-Tutorial werden Sockets folgendermaßen definiert [5] [5]:

"A socket is one end-point of a two-way communication link between two programs
running on the the network. Socket classes are used to represent the connection between
a client program and a server program. The java.net package provides two classes--
Socket and ServerSocket--that implement the client side of the connection and the server
side of the connection, respectively."

Diese doch recht allgemeine Formulierung ist natürlich nach den Ausführungen in Kapitel 1 nicht ausreichend. "UDP-Sockets" und „TCP-Sockets" unterscheiden sich grundlegend - das wird natürlich auch in Java berücksichtigt - in Form unterschiedlicher Klassen innerhalb der java.net package (vgl. Anhang A: Übersicht java.net-package). In diesem „Paket" finden sich alle Klassen, welche zur Kommunikation über Netzwerke notwendig sind. Klassen zur Fehlerbehandlung, zur Dekodierung von Internet-Adressen (URL) und auch die Socketklassen:


UDP: DatagramSocket.class

und

DatagramPacket.class

und

MulticastSocket.class


TCP: Socket.class

und

ServerSocket.class

und

SocketImpl.class



Letztere ist eine abstrakte Klasse welche die Kommunikations-API implementiert. Sie wird von Stream-Socketverbindungen benutzt. In dieser Klasse müssen Java-Lizenznehmer ihre Protokolle implementieren (z.B.: IPX/SPX, AppleTalk).



Abb. 2.1: Vorgehen zum Aufbau einer Socketverbindung mit Java

Abb. 2.1 demonstriert das Vorgehen zum Aufbau einer Socketverbindung mit Java. Methoden wie bind() (vgl. Kapitel 1) sind in der API verborgen und der Programmierer muß sie nicht gesondert aufrufen. Durch das Verbergen dieser Details sind mit Java sehr kurze und verhältnismäßig leistungsstarke Programme möglich. So wurden inzwischen primitive HTTP-Webserver in Java programmiert, mit weniger als 200 Zeilen-Quellcode [6] [6].





2.2 "Die Kommunikationsklassen"

2.2.1 Socket.class

Diese Klasse implementiert eine "streamed socket", d.h. die Methoden getInputStream() und getOutputStream(), die in Kapitel 2.3 erläutert werden. Sie enthält weiterhin Methoden zum Schließen des Socket, zur Auflösung einer URL-Adresse und zur Abfrage der Portnummer und IP-Adresse etc. Im Falle eines Kommunikationsfehlers "wirft" diese Klasse eine IOException, eine SocketException oder eine UnknownHostException aus, welche entsprechend behandelt werden muß (vgl. Anhang B: Beispielprogramm "DayTimeClient").



2.2.2 ServerSocket.class

Diese Klasse ist ein Spezialfall der Socket-Klasse eben für Server. Mit ihr können auch einige Parameter einer Netzwerkverbindung eingestellt werden (z.B. "Timeouts"). Als wichtigste Methode implementiert sie die in Kapitel 1 erwähnte accept()-Methode. Diese Methode ist nur auf Serverseite sinnvoll - wird sie abgearbeitet wartet der Server auf eine Anforderung eines Clienten. In der Java-API ist sie so implementiert, daß es sich aus Programmierersicht um einen "echten Block" handelt. D.h. die Programmausführung wird (im aktuellen Thread) solange an der accept()-Methode gestoppt, bis diese ein Client-Objekt zurückliefern kann, d.h. bis ein Client Kontakt mit dem Server aufgenommen hat. Sie muß also nicht in eine Schleife eingebunden werden noch ist ein Test des zurückgelieferten Objekts auf NULL notwendig! Diese Leistungen sind komplett in der API integriert (vgl. Anhang C: Beispielprogramm "DayTimeServer").



2.2.3 SocketImpl.class

Ist eine abstrakte Klasse, welche die Socket-Methoden definiert, die die Java-Lizenznehmer für ihre jeweilige Plattfrom implementieren. So würden in dieser Klasse Anpassungen an beispielsweise IPX/SPX oder Appletalk erfolgen. Diese Klasse wird ein "herkömmlicher" Java-Programmierer niemals direkt benötigen, wobei die meisten Methoden dieser Klasse bereits bekannt sind!



2.2.4 DatagramPacket.class

Diese Klasse kapselt die Datagram-Pakete des UDP. Der Paketinhalt wird in Form eines "Array of Byte" übergeben und kann dann entsprechend über eine Socketverbindung im Netz verteilt werden. Ebenfalls werden ankommende Pakete in diese Klasse hineingelesen, ehe sie mit den entsprechenden Methoden getData(), getLength() usw. bearbeitet werden können.



2.2.5 DatagramSocket.class

Wie zu erwarten legt diese Klasse eine Socketverbindung zum empfangen und versenden von Datagram-Paketen an. Die Klasse bietet u.a. zwei Methoden send() und receive() an, welche - je nachdem - auf ein Datagram-Paket warten oder es verschicken. Bei receive() wird solange gewartet, bis tatsächlich ein Paket eingetroffen ist. Eine Überprüfung auf NULL ist also auch hier nicht notwendig.



2.2.6 MulticastSocket.class (ab JDK 1.1)

Die "MulticastSocket.class" ist eine spezielle Klasse für einen netzwerkweiten Datagram-Broadcast. Wie bereits erwähnt gibt es Fälle, in denen ein solches Vorgehen aufgrund der höheren Performance von UDP-Datagrammen sinnvoll ist. Die Klasse ist vollständig von der oben beschriebenen Klasse "DatagramSocket.class" abgeleitet.





2.3 Streams

Streams stellen den Datentransfermechanismus der "stream sockets" dar. Um das Beispiel des Telefonierens wieder aufzugreifen - Streams sind mit der eigentlichen Unterhaltung (dem Gespräch) vergleichbar, wohingegen Sockets „nur" die Verbindung darstellen. Betriebssysteme verwenden Streams für nahezu alle Kommunikationsaufgaben, wie z.B. eine Druckerausgabe oder einen Festplattenzugriff. Sie bieten einen Ein-/Ausgabe-Mechanismus an, der die entsprechenden Endgeräte kapselt und verbirgt. Das Schreiben eines Streams ist viel einfacher als das Lesen. Der Empfänger muß beispielsweise auch das Ende des Streams erkennen.

Die Stream-Klassen von Java befinden sich nicht im java.net-, sondern im java.io-Paket. Wie gesagt, lassen sich Streams auch für Aufgaben des Betriebssystems nutzen und ihre Leistungsfähigkeit übersteigt leicht "einfache Netzoperationen" (der java.net-Klasse).

Um Streams auf einer Socketverbindung nutzen zu können, kann von der Socketklasse ein Streamobjekt angefordert werden: getInputStream/getOutputStream. Dieses Objekt kann dann mit einem "FilteredStream" o.ä. aus der IO-Klasse verknüpft werden und der erfolgreichen Datenübertragung steht nichts mehr im Wege.

Auch komplexe Objekte können über Streams übertragen werden. Java bietet mit der Serializable-Schnittstelle eine einfache Möglichkeit auch solche zu verschicken. Die Auflösung der Referenzen übernimmt hierbei auch Java. So bekommt jeder String , jede Integer usw. des zu übertragenden Objekts ein sogenanntes Handle. Java kann dann „erkennen", welche Objekte bereits übertragen wurden und vermeidet auch eine Endlosschleife bei ringartigen Verküpfungen (z.B.: class A refernziert class B und umgekehrt). Solche komplexen Objekte werden auf der Seite des Empfängers wieder identisch im Speicher abgebildet!

Eine weitere Beschäftigung mit Streams würde den Rahmen des Seminars sprengen, deshalb wird nicht weiter darauf eingegangen.





Zusammenfassung Kapitel 2:

In der Java-API sind viele Socket-Spezifischen Schnittstellen und Methoden gekapselt und der Programmierer ist von ihrer Nutzung entbunden. Die API unterscheidet hierbei Methoden und Klassen für „streamed sockets" zur Nutzung mit TCP und "Datagram Sockets" für UDP. Durch die Verwendung von "Streams" können über diese Verbindungen sehr schnell Datenströme verschickt werden.

zu Kapitel 3 Kapitelanfang zum Inhalt