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 nicht 🙂

    Hier 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, obwohl login 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-Teil

    while (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?


Anmelden zum Antworten