# Chat Programm. Verständnisfrage while-Schleife



## Feliband (18. Sep 2007)

Hi, 

ich habe hier einen Chatserver und einen Client aus dem Java HeadFirst Buch. Es funktioniert alles.

In der Methode IncomingReader verstehe ich nicht wieso die while-Schleife in Zeile 93 keinen Endlostext in der Konsole oder GUI ausgibt. message wird doch niemals null. Ich meine es müsste unendlich "read " auf der Konsole ausgegeben werden. Was verstehe ich da falsch?

Hier der Quelltext für den Client und den Server:


```
import java.io.*;
import java.net.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class SimpleChatClient {

    JTextArea incoming;
    JTextField outgoing;
    BufferedReader reader;
    PrintWriter writer;
    Socket sock;

    public static void main(String[] args) {
       SimpleChatClient client = new SimpleChatClient();
       client.go();
    }

   public void go() {

       // build gui

        JFrame frame = new JFrame("Simple Chat Client");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel mainPanel = new JPanel();
        
        incoming = new JTextArea(15,20);  // was 15,50
        incoming.setLineWrap(true);
        incoming.setWrapStyleWord(true);
        incoming.setEditable(false);
       
        JScrollPane qScroller = new JScrollPane(incoming);
        qScroller.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        qScroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        

        outgoing = new JTextField(20);
        

        JButton sendButton = new JButton("Send");
        sendButton.addActionListener(new SendButtonListener());

        
        mainPanel.add(qScroller);
        mainPanel.add(outgoing);
        mainPanel.add(sendButton);
        
        setUpNetworking();
        Thread readerThread = new Thread(new IncomingReader());
        readerThread.start();
      
        frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
        frame.setSize(400,500);
        frame.setVisible(true);
                
   
     } // close go

   private void setUpNetworking() {  
        try {
           sock = new Socket("localhost", 5000);
           InputStreamReader streamReader = new InputStreamReader(sock.getInputStream());
           reader = new BufferedReader(streamReader);

           writer = new PrintWriter(sock.getOutputStream());
          
           System.out.println("networking established");
        } catch(IOException ex) {
           ex.printStackTrace();
        }
     } // close setUpNetworking   

   public class SendButtonListener implements ActionListener {
      public void actionPerformed(ActionEvent ev) {
          try {
             writer.println(outgoing.getText());
             writer.flush();
             
          } catch(Exception ex) {
             ex.printStackTrace();
          }
          outgoing.setText("");
          outgoing.requestFocus();
      }
    }  // close SendButtonListener inner class

  public class IncomingReader implements Runnable {
     public void run() {
           String message;             
           try {
             while ((message = reader.readLine()) != null) {
                System.out.println("read " + message);
                incoming.append(message + "\n");
    
              } // close while
           } catch(Exception ex) {ex.printStackTrace();}
       } // close run
   } // close inner class
```


```
import java.io.*;
import java.net.*;
import java.util.*;

public class VerySimpleChatServer {

    ArrayList<PrintWriter> clientOutputStreams;


    public class ClientHandler implements Runnable {

         BufferedReader reader;
       
         Socket sock;
   

         public ClientHandler(Socket clientSocket) {
           try {
             sock = clientSocket;
             InputStreamReader isReader = new InputStreamReader(sock.getInputStream());
             reader = new BufferedReader(isReader);
              
           } catch(Exception ex) {ex.printStackTrace();}
          } // close constructor

        public void run() {
           String message;
             
           try {

             while ((message = reader.readLine()) != null) {
                
                System.out.println("read " + message);
                tellEveryone(message);
    
              } // close while
           } catch(Exception ex) {ex.printStackTrace();}
       } // close run
   } // close inner class
      



     public static void main (String[] args) {
         new VerySimpleChatServer().go();
    }

     public void go() {
      clientOutputStreams = new ArrayList<PrintWriter>();

       try {
       ServerSocket serverSock = new ServerSocket(5000);

       while(true) {
          Socket clientSocket = serverSock.accept();
          PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());         
          clientOutputStreams.add(writer);

       Thread t = new Thread(new ClientHandler(clientSocket));
       t.start();


       System.out.println("got a connection");
     }
       // now if I get here I have a connection
               
      }catch(Exception ex) {
         ex.printStackTrace();
      }
   }

   public void tellEveryone(String message) {
      Iterator it = clientOutputStreams.iterator();
      while(it.hasNext()) {
        try {
           PrintWriter writer = (PrintWriter) it.next();
           writer.println(message);
           writer.flush();
         } catch(Exception ex) {
              ex.printStackTrace();
         }
      
       } // end while
       
   } // close tellEveryone


}
```
[/code]


----------



## SlaterB (18. Sep 2007)

message = reader.readLine()
wird doch ständig neu gesetzt, nur wenn im reader was drin ist, kommt eine ordentliche message,
nach kurzer Zeit ist null erreicht, die Schleife bricht ab,


----------



## HoaX (18. Sep 2007)

lies doch einfach die apidoc zu readLine? es blockiert den ablauf bis eine vollständige zeile verfügbar ist. und das != null sorgt dafür, dass wenn der stream zu ende ist abgebrochen wird.


----------



## Feliband (19. Sep 2007)

Danke für die schnellen Antworten. 

Das verstehe ich ja gerade nicht, die while-Schleife wird nicht abgebrochen. Sie müsste doch abbrechen, nachdem ich meinen Text abgesendet habe, oder? Sie läuft aber weiter und und gibt jedesmal Text aus, wenn eine Nachricht abgesendet wurde, was ja auch richtig ist, da auf eingehende Nachrichten gewartet werden soll.


----------



## SlaterB (19. Sep 2007)

erst sagst du, du verstehst nicht, warum es keine Endlosschleife gibt und nun genau andersrum?..

> ie läuft aber weiter und und gibt jedesmal Text aus

generiert die Schleife sich zufällig ausgedachten Text oder wie 
WELCHER Text kommt da?

-------

oder meinst du, dass die Operation wartet statt abzubrechen?,
(sag doch mal deutlich was passiert und was du meinst...)
das ist normal, siehe Antwort Hoax


----------



## Angel4585 (19. Sep 2007)

du musst noch ein writer.newLine(); oder sowas senden


----------



## sparrow (19. Sep 2007)

Ich finde diese Konstruktion für die while-Schleife auch sehr unleserlich.
Nach einer Weile in Java gewöhnt man sich aber dran.
Du könntest das ganze auch so schreiben:


```
while (true) { 
   
   message = reader.readLine();
   if (message == null) {
      break;
   } else {
      System.out.println("read " + message); 
      tellEveryone(message); 
   }

}
```


Diese Schleife prüft die Bedingung nicht am Anfang sondern in der Schleife selbst.
Sie blockiert so lange in Zeile 3 bis eine vollständige Zeile angekommen ist, oder aber die Verbindung abegabut wurde.
Wird die Verbindung abgebrochen ist der Rückgabewert von reader.readLine() null, die Schleife wird abgebrochen.
Ansonsten wird die Rückgabe von reader.readLine() ausgegeben.


Gruß
Sparrow


----------



## Guest (19. Sep 2007)

Vielen Dank. Ich wusste nicht, dass readLine() blockiert. 

Hätte ich hier nachlesen können. 

http://www.java-forum.org/de/viewtopic.php?t=6033&start=0&postdays=0&postorder=asc&highlight=

Na ja.


----------

