Java 7 Grundkurs

Zu Fuß verbinden: Sockets

LinkedIn Learning kostenlos und unverbindlich testen!

Jetzt testen Alle Abonnements anzeigen
Zwei Java-Programme auf verschiedenen Rechnern können miteinander kommunizieren, indem man sie über das Netzwerk mittels Sockets miteinander verbindet. Wie Sie das auch in Ihren eigenen Programmen einsetzen können, erfahren Sie in diesem Video.
14:38

Transkript

Zwei Java Programme, die auf verschiedenen Rechnern laufen, können miteinander kommunizieren, indem sie eine Netzwerkverbindung über Sockets aufbauen. Eines der beiden Programme agiert dabei als Server, das andere als Client. Das heißt der Server bietet einen Dienst an, den der Client gerne nutzen möchte. Damit das Java Programm auf dem Server von außen erreicht werden kann, horcht es an einem bestimmten Port auf eingehende Verbindungen. Hier z.B. am Port 7777. Den Port können Sie prinzipiell frei wählen, Sie müssen nur darauf achten, dass kein anderes Programm diesen Port bereits belegt. Hier kommt der Socket ins Spiel. Das ist ein Endpunkt für eine zweiseitige Kommunikation über den sowohl Daten gesendet, als auch empfangen werden können. Der Server baut sich nun also einen solchen Socket, genauer ein ServerSocket, und dann sitzt der da und wartet auf eingehende Verbindungen. Irgendwann kommt dann ein Client des Weges und möchte eine Verbindung zu diesem Server aufbauen. Der Client erstellt dazu seinerseits ebenfalls einen Socket und teilt diesem mit, zu welchem Server er sich gern verbinden möchte. In unserem Beispiel hier also über die Angabe der IP-Adresse des Servers 192.168.100.5 und den Port 7777. Der ServerSocket auf dem Server ist nun aber nicht für die Kommunikation da, sondern lediglich für den Verbindungsaufbau. Wenn ein Client sich bei ihm meldet und eine Verbindung aufbauen möchte, dann sucht dieser ServerSocket serverseitig nach einem freien Port, öffnet dort einen normalen Socket, der dann für die Kommunikationsverbindung mit dem Client zuständig ist. Nun steht die Verbindung zwischen Client und Server. Der Client kann an den Server Daten senden, der Server kann die Daten in Empfang nehmen, kann Antworten zurück schicken und so können sich nun also beide Seiten unterhalten, solange bis eine der beiden Seiten die Verbindung beendet. In der Zwischenzeit sitzt der ServerSocket weiter auf seinem Port 7777 und wartet darauf, dass weitere Clients eine Verbindung aufbauen möchten. Auf diese Weise ist der Server also in der Lage mehrere Clients gleichzeitig zu bedienen. Ein Client meldet sich auf dem Server an, bekommt einen eigenen Port auf dem Server zugeteilt, für die Kommunikation, und dann kann sich der nächste Client anmelden. Jetzt machen wir das ganze mal praktisch. Ich beginne mit einem leeren, neuen Java Projekt, drücke also auf "File", "New Project", Kategorie "Java" und hier auf "Java Application" und dann "Next". Ich nenne diese Anwendung "Sockets". So, die Anwendung ist erstellt, schauen wir noch kurz nach, ob es wirklich eine Java 7 Anwendung wird. Also mit der rechten Maustaste auf das Projekt klicken, ganz unten "Properties" auswählen und hier im Bereich "Source" ganz unten "JDK 7" ankreuzen. OK, beginnen wir mit dem Serverprogramm. Ich erstelle dazu eine neue Java-Klasse. Also auf "Source Packages" rechte Maustaste "New" "Java Class". Die Klasse nenne ich "Demoserver". Die Klasse sollte ja danach benannt werden, was sie tut, wofür sie verantwortlich ist. Unser Server macht aber nun einmal nicht viel mehr, als zu demonstrieren wie es funktionieren soll. Außerdem geben wir natürlich noch ein Package an -- "Com.video2brain.Java7.sockets" und hier das Paket "Server", da kommt der Server rein. Dann drücke ich auf "Finish". Nun wird die Klasse erzeugt. Damit wir das Serverprogramm starten/ausführen können, brauchen wir eine Main-Methode. Also fügen wir die ein: "psvm" Tabulator-Taste, nun haben wir unsere Main-Methode. Als erstes müssen wir uns hier nun einen Server-Socket bauen. Die Klasse dafür heißt bequemerweise "ServerSocket". Ich schreibe hier also hin "newServerSocket", ich kann auch Strg+Leertaste verwenden, auf dem Weg dahin, und schauen ob NetBeans etwas vorschlägt. Hier haben wir schon Server -- noch ein "s" hin , da haben wir "ServerSocket". Es befindet sich im Paket "Java.net". Dieser ServerSocket möchte nun gern wissen, auf welchen Port er horchen soll. -- Hier. -- Also geben wir als Port 7777 an, "Enter". Jetzt brauchen wir noch eine Variable um diesen ServerSocket ansprechen zu können, da können wir hier auf das Lämpchen klicken "assign return value to new variable" und dann bekommen wir hier unsere neue Variable. Die ist natürlich vom Typ "ServerSocket" und heißt jetzt auch einfach "ServerSocket", was wir auch so lassen können. Beim Erstellen eines solchen ServerSockets kann eine I/O Exception geworfen werden, die müssten wir jetzt natürlich fangen. Lassen wir das mal NetBeans generieren, um uns ein wenig Tipparbeit zu sparen "surround statement with try/catch". Dann sieht das so aus. Wenn wir den ServerSocket nicht mehr benötigen, müssen wir ihn schließen, indem wir seine Close-Methode aufrufen. Wir können das aber auch die Laufzeitumgebung machen lassen, indem wir hier das "try with resources" verwenden, d.h. also hinter dem "try" in runden Klammern den ServerSocket kreieren, die Ressource angeben, die wir gerne automatisch verwaltet haben möchten und nun sorgt die Laufzeitumgebung dafür, dass dieser ServerSocket geschlossen wird, wenn wir den try-Block verlassen. Jetzt haben wir den Socket erzeugt, nun müssen wir noch dafür sorgen, dass er auch an diesem Port auch tatsächlich horcht. Dafür gibt es eine Methode, die heißt -- ich muss hier vorne mal ein kleines "s" hinsetzen, das ist nämlich die Variable -- "ServerSocket.except". Diese Methode blockiert nun, die sitzt da und wartet. Das Programm läuft nicht weiter, solange bis irgendwann einmal ein Client versucht sich zu verbinden. Wenn er dies tut, dann erzeugt diese Except-Methode, wie wir ja gerade in der Grafik gesehen haben, einen neuen Socket und gibt diesen zurück. Wir merken uns also den Socket in einer Variablen, können wieder hier darauf klicken -- "assign return value" und wir nennen den Socket aber nicht "Except", wir nennen ihn "Client Socket". Das ist jetzt der Socket für die Kommunikation mit dem Client. Nun hatte ich ja gesagt wir können über den Socket Daten senden und auch Daten empfangen. Um dies tun zu können müssen wir uns jetzt von diesem Socket zwei Streams holen, einen "InputStream" und einen "OutputStream". Über den "InputStream" können wir Daten empfangen und über den "OutputStream" können wir Daten senden. Ich schreibe also "InputStream in = ClientSocket", immer mit Strg+Leertaste arbeiten, man spart sich eine Menge Tipparbeit -- "ClientSocket." -- ganz oben steht schon "getInputStream", also einfach "Enter" drücken und das gleiche für die Gegenrichtung "OutputStream out = ClientSocket.getOutputStream". So, jetzt haben wir die Kommunikationsstrecke aufgebaut. Ab hier kann der Server jetzt also Daten empfangen und Daten senden. Eine Kommunikation über "InputStream" und "OutputStream" ist allerdings sehr kompliziert und sehr low-level, deswegen können wir vor diese Streams noch andere Streams davor schalten, z.B. "DataInputStream" und "DataOutputStream". Mit "InputStream" und "OutputStream" kann ich ja nur einzelne Zeichen oder Byte-Areas austauschen. Diese beiden Klassen machen das alles ein bisschen komfortabler. Hier habe ich die Möglichkeit, Java-Typen hin und her zu schieben. Dafür gibt es dann die passenden Methoden im "DataOutputStream", also z.B. ein "WriteDouble" oder ein "WriteInt", "WriteLong", usw. Wenn ich Strings übergeben möchte, dann heißt die Methode "WriteUTF". Im "DataInputStream" dann die entsprechenden Methoden zum Lesen, also "ReadByte", "ReadDouble", "ReadFloat" und "ReadUTF". Bauen wir das also noch in unseren Server ein. Also "DataInputStream" -- achten Sie darauf und nehmen Sie den aus Java.io, mit CORBA wollen wir hier nichts machen. Also "DataInputStream" -- ich nenne ihn "DataIn", "new DataInputStream" und hier wird als Parameter für den Konstruktor schon "in" vorgeschlagen. Das ist richtig also einfach "Enter" drücken und ein Semikolon hinten dran. Das gleiche in die Gegenrichtung "DataOutputStream", auch hier wieder Paket Java.io verwenden -- "DataOut = new DataOutputStream out". Um das Schließen all dieser Streams müssen wir uns übrigens nicht kümmern, wenn der Socket geschlossen wird zu dem sie gehören, dann werden auch die Streams korrekt geschlossen. Für Demonstrationszwecke macht dieser Server jetzt nicht viel mehr als das, was er rein bekommt, einfach wieder zurück zu geben. Wir holen uns also aus dem "DataInputStream" einen String und schreiben ihn nach "DataOut" wieder raus. Also, "string Nachricht = DataIn.readUTF" und dann das ganze raus schreiben nach "DataOut.writeUTF" heißt die Methode. Da unten ist sie -- "WriteUTF" und die Nachricht großschreiben. Damit ist der Server fertig, jetzt fehlt uns noch der passende Client. Dafür legen wir eine zweite Klasse an. Ich drücke hier einmal auf dieses Package mit der rechten Maustaste und sage "New-Java Class". Die nenne ich jetzt "Demo Client". Im Paket "Com.video2brain.Java7.sockets.client". -- Genau. -- OK, auch hier brauchen wir wieder eine Main-Methode, denn der Client soll ja als unabhängiges Programm laufen können, "psvm" und Tabulator-Taste. Da das hier der Client ist brauchen wir hier keinen ServerSocket, sondern nur einen normalen Socket, d.h. wir schreiben einfach "new Socket" -- und dieser Konstruktor, der möchte jetzt zwei Parameter, nämlich "Wo befindet sich der Server?" und "Auf welchen Port sollen wir horchen?". Da bei mir jetzt beide Programme auf demselben Rechner laufen, gebe ich als Server "localhost" an. Damit sieht der Aufruf dann so aus -- "localhost" und auf Port 7777. Das muss natürlich derselbe Port sein, auf dem der Server auch tatsächlich horcht. Rückgabewert merken, in einem variablen Socket, ja das können wir so lassen. Auch hier kann wieder eine Exception geworfen werden, die wir natürlich abfangen müssen "Surround statement mit try/catch". Sie sehen es können sogar zwei verschieden Exceptions entstehen "UnknownHostException" und "I/O Exception". Auch dieser Socket muss natürlich geschlossen werden, wenn er nicht mehr benutzt wird. Also machen wir auch hier ein "try with resources" daraus, damit das Schließen des Sockets in jedem Fall und automatisch funktioniert. In dem Moment, wo der Client diesen Sockel erfolgreich aufgebaut hat, steht die Verbindung zum Server, d.h. der Client kann sich jetzt hier InputStream" und "OutputStream" holen. Das ist also das gleiche wie das, was auf dem Server bereits ablief, nur dass ich es hier etwas kürzer fasse, indem ich das in nur zwei Zeilen schreibe, statt in vier. Das sieht dann so aus "DataInputStream", nennen wir es wieder "DataIn" "newDataInputStream" und hier als Parameter kommt jetzt unser "socket.getInputStream" rein. Genau -- das gleiche für die Gegenrichtung "DataOutputStream DataOut = new" Strg+Leertaste "DataOutputStream" und hierein wieder "socket.getOutputStream", mit "Enter" bestätigen, nochmal "Enter" und Semikolon dran, fertig. Die Kommunikationsverbindung steht und jetzt können wir einen Text senden, "DataOut.writeUTF" -- hier kommt der Text rein. Nachdem der Client seinenText gesendet hat, horcht er auf die Antwort -- an seinem InputStream "DataIn.readUTF". Die Antwort die da angekommen ist, die geben wir dann hier zur Kontrolle aus, "sout" Tabulator-Taste wird zu "system.out.println". Der Server sagt: "Antwort". Damit ist auch der Client fertig und wir können unsere Anwendung testen. Dazu starten wir zuerst einmal den Server, also erstmal speichern wir natürlich alles. Jetzt starten wir den Server -- "Run File" -- wie wir sehen, sehen wir nichts, d.h. hier unten können wir es sehen: Der Server läuft. Gehen wir zum Client und starten den Client -- auch "Run File" und dann sehen wir der Client sagt, dass der Server sagt "Hallo Server". Unser Server ist nun so programmiert, dass er exakt einen Client entgegennimmt, ihm einmal eine Antwort gibt und dann Feierabend macht. In der Praxis würden hier natürlich noch zwei Erweiterungen reinkommen, nämlich die erste, dass der Server in einer Schleife immer wieder neue Anfragen von diesem Client entgegennimmt, um sie dann beantworten zu können und das zweite, dass der Server jeden Client in einem separaten Prozess bearbeiten würde. Damit wir hier auch tatsächlich den Vorteil nutzen können, dass der Server Socket ja eigentlich frei ist, damit weitere Clients sofort wieder verbinden können, während der erste Client noch bedient wird. Das können Sie gerne als Übungsaufgabe einmal ausprobieren. Wenn Sie Fragen dazu haben sollten oder damit nicht weiter kommen sollten, schicken Sie mir einfach eine E-Mail. Sie haben nun also gesehen, wie die Kommunikation über Sockets aussieht, und dass die beiden Klassen "Socket" und "ServerSocket" das ganze eigentlich recht einfach machen. Wichtig ist nur, dass beide Seiten, also Client und Server, sich irgendwie auf ein Protokoll einigen, dass also der Server weiß, was er vom Client in welcher Reihenfolge zu erwarten hat, und dass der Client weiß, wie er die Antwort des Servers zu verstehen hat.

Java 7 Grundkurs

Machen Sie sich mit den Grundlagen der Java-Programmierung vertraut und lernen Sie die Syntax der Sprache sowie das Konzept der objektorientierten Softwareentwicklung kennen.

8 Std. 32 min (66 Videos)
Derzeit sind keine Feedbacks vorhanden...

Dieser Online-Kurs ist als Download und als Streaming-Video verfügbar. Die gute Nachricht: Sie müssen sich nicht entscheiden - sobald Sie das Training erwerben, erhalten Sie Zugang zu beiden Optionen!

Der Download ermöglicht Ihnen die Offline-Nutzung des Trainings und bietet die Vorteile einer benutzerfreundlichen Abspielumgebung. Wenn Sie an verschiedenen Computern arbeiten, oder nicht den ganzen Kurs auf einmal herunterladen möchten, loggen Sie sich auf dieser Seite ein, um alle Videos des Trainings als Streaming-Video anzusehen.

Wir hoffen, dass Sie viel Freude und Erfolg mit diesem Video-Training haben werden. Falls Sie irgendwelche Fragen haben, zögern Sie nicht uns zu kontaktieren!