Server-Programmierung und Streams
-
Hio!
Ich habe gerade einen kleinen Server und einen kleinen Client in java programmiert, was soweit auch gut rennt, nur zwei Fragen habe ich dazu:
1. Zum Schreiben und Lesen habe ich nun mittlerweile mehrere Varianten von Streams gesehen, PrintStream, WriteStream, BufferedReader, InputStream, OutputStream etc. pp. Die Varianten scheinen in der Anwendung unterschiedlich komplex zu sein, aber entsprechend auch unterschiedliche Möglichkeiten zu haben? Was nutze ich denn am geschicktesten und einfachsten, wenn man in in C++-ähnlicher Manier ein "std :: cout << " oder "std :: cin >>" haben will? (also bezogen auf die Einfachheit der Anwendung natürlich)
2. Muss ich für jede Übertragung eine neue Verbindung aufbauen oder kann ich eine Verbindung aufbauen und über diese mehrere Kommunikationen ausführen? Also folgendes:
Der Client verbindet sich mit dem Server, der Server nimmt diese Verbindung mittels accept() an und es kommt zu einer Datenübertragung. Der Server nimmt die Daten des Clients an, macht was und schickt sie zurück.
Kann ich nun den server auf weitere Daten warten lassen (ohne accept()!), d.h. mit der selben Verbindung / Port?
Mir ist klar, dass der Server, sofern nicht mit Threads gebaut, dann keine anderen Verbindungen mehr zulässt, aber das möchte ich auch erstmal gar nichtHier mal ein Auszug aus meinem Code
Socket client = null; BufferedReader in = null; PrintStream out = null; try { client = derServer.accept(); in = new BufferedReader( new InputStreamReader(client.getInputStream())); out = new PrintStream(client.getOutputStream()); System.out.println("Eingehende Verbindung... Erhalte folgendes:"); } catch(IOException e) { System.out.println("Fehler bei der Verbindung"); } while(in != null && out != null) { //endlosschleife try { if ( /* Weitere Daten angekommen */ ) { String incoming = in.readLine(); System.out.println(incoming); //mit Sternchen zurückschicken out.println("**" + incoming + "**"); }
Gruß Pille
-
Hallo, zu deinen Fragen:
Die Wahl der Stream-Klassen hängt halt stark vom verwendeten Datenformat ab. Ich schreibe zum Beispiel grad einen Webserver und nutze für eingehende Streams einen BufferedReader und für ausgehende Streams einen PrintWriter, da diese Klassen auf die Übertragung von Zeichenketten zugeschnitten sind.
Bei einer Socketverbindung über TCP wie in deinem Beispielcode kann man natürlich beliebig viele Daten hin und herschicken. Die accept-Methode des Servers liefert dir das Socket, welches eine Punkt-zu-Punkt-Verbindung darstellt. Aus dem Socket kannst du dann uneingeschränkt lesen und reinschreiben, die Korrektheit der Daten ist sichergestellt. Willst du einen Dialog zwischen Client und Server haben, musst du ein entsprechendes Protokoll einführen, damit Client und Server "die selbe Sprache sprechen". Eine einfache Variante ist zum Beispiel, wenn jeder Befehl in einer Zeile steht. Der Server liest nachdem die Verbindung aufgebaut ist einfach eine Zeile mittels readLine() ein, interpretiert was in der Zeile steht und schickt die Antwort dann zurück. Anschließend liest er die nächste Zeile ein. Wenn du in die JAVA-API schaust, wirst du feststellen, dass die meisten Leseoperationen von Eingabeströmen blockierend sind. Sind also gerade keine Daten verfügbar, wird gewartet. Die Verbindung wird erst beendet, wenn das Socket geschlossen wird.
-
Okay, mir scheint dann brauche ich wohl ein BufferedReader und PrintWriter, weil mir geht es zum Großteil auch um Textdaten - der Server ist erstmal für nichts zu gebrauchen, lerne ja noch *g*
Könntest du mir ein Beispiel posten für das von dir beschriebene Protokoll? Weil genau das möchte ich realisieren!
In Pseudocode würde ich so vorgehen:socket = server.accept(); //Stelle eine (und damit nur genau eine!) Verbindung her while(true) { leseEineZeileVomClient(); verarbeiteDaten(); schickeDatenZurück(); } socket.close();
-
Du willst auch einen Webserver programmieren? Ich würde erstmal mit etwas ganz simplen anfangen.
Zunächst brauchst du eine Funktion zum Senden einer Zeile und zum Empfangen einer Zeile.
Und dann kannst du anfangen Befehle einzubauen:
BEFEHL PARAMETER1 PARAMETER2
Zum Beispiel:
ADD 100 200
Der Server liest die Zeile ein und erkennt den Befehl Add. Er liest beide Parameter ein und gibt die Summe beider zurück:
RES 300
Damit hättest du ein einfaches Protokoll entwickelt. Das mit den Rechenoperationen war nur ein Beispiel, du kannst natürlich auch eine Messagebox ausgeben oder ähnliches...
Du könntest auch eine Art Login bauen. Dazu hast du für jeden Client eine Variable vom Typ Boolean
login
. Diese steht anfangs auf false.Ein Client muss dann folgendes senden:
LOGIN IrgendeinPassword
Empfängt der Server dies, und ist das Passwort korrekt, so wird
login
auf true gesetzt. Empfängt der Server einen anderen Befehl, obwohllogin
noch false ist, wird die Verbindung wieder getrennt, usw.Das nur als Anregung, was ein Protokoll sein kann.
-
Ich habe gerade einen Echo-Server fertiggestellt, wollte nie einen Webserver bauen
Nur ein Echo-Server verarbeitet ja auch Textdaten, darum. Habe es nun aber heute morgen mehr oder weniger geschafft, das Problem lag wohl zum Großteil bei den Streams, da ich nie so wirklich mit denen gearbeitet habe.
Hier mal der wichtige Server-Teilwhile (true) { Socket clientSocket = derServer.accept(); BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); PrintWriter out = new PrintWriter(clientSocket.getOutputStream()); String s; while ((s = in.readLine()) != null) { System.out.println("Erhalte: " + s); out.println("**" + s + "**"); //out.flush(); out.println("end"); //Um den Client zu sagen, dass keine weiteren Daten kommen out.flush(); }
Nur nochmal zur Sicherheit: Sehe ich es richtig, dass ich bei einem PrintWriter immer ein flush() aufrufen muss um die Daten dann wirklich zu schreiben? Also buffert ein PrintWriter alle Daten und schreibt sie dann per flush() alle aufeinmal oder?