# Ich seh den Wald vor lauter Bäumen nicht.



## Tahomar (29. Nov 2006)

*Hallo,

ich versuche einen einfachen Chat zwischen Client und Server zu basteln und habe dazu auch schon versucht die hier im Forum (und auch anderswo) verfügbaren Infos für mich nutzbar zu machen, jedoch ohne Erfolg. Ich habe drei Programme:*


```
//Server.java
import java.net.*;
import java.io.*;
public class Server 
{
 public static void main(String args[])
	{
	 int port=1234;
	 System.out.println("Der Server wurde gestartet und wartet auf einen Client am Port: "+port+"\nBeenden mit STRG+C\n");
		
		try
		{
		 //Öffnen einer Verbindung und horchen am Port,
		 //ob sich ein Client versucht zu verbinden
		 ServerSocket horchposten=new ServerSocket(port);
		Socket client;

		while(true)
		{
		 client=horchposten.accept();
		// kommunikation an einen nebenläufigen Thread abgeben
		ServerThread t = new ServerThread(client);
		t.start();
		// und wieder auf neue Verbindungen warten 
		}
		
		
		}
		
		 catch(Exception ex)
			{
			 System.err.println("Es ist ein Kommunikationsfehler aufgetreten. Das System meldet:\n"+ex+"\n");
			 ex.printStackTrace();
			 System.exit(1);
			}
	}
}
```

------------------------------------------------------



```
//ServerThread.java

import java.net.*;
import java.io.*;


public class ServerThread extends Thread {
private Socket client;
public ServerThread(Socket client) {
this.client = client;
} 

public void run()
{ 

try
{		
		InputStream eingehend = client.getInputStream();
		BufferedReader SocketRein=new BufferedReader (new InputStreamReader(eingehend));
		String NachrichtRein=SocketRein.readLine();
		System.out.println("Client sagt: "+NachrichtRein+"\n");
		
		System.out.println("Was möchten sie dem Mitarbeiter sagen?\n");
		BufferedReader SocketEingabe=new BufferedReader(new InputStreamReader(System.in));
		String NachrichtRaus=SocketEingabe.readLine();

		OutputStream ausgehend=client.getOutputStream();
		PrintWriter SocketRaus=new PrintWriter (ausgehend,true);
		SocketRaus.println(NachrichtRaus);
		System.out.println("Der Server sendet folgende Nachricht zum Mitarbeiter: \n"+NachrichtRaus);
		
		SocketRaus.println();
		SocketRaus.flush();
		SocketEingabe.close();
		SocketRaus.close();
		client.close();
}
catch(Exception ex)
{
			 System.err.println("Es ist ein Kommunikationsfehler aufgetreten. Das System meldet:\n"+ex+"\n");
			 ex.printStackTrace();
			 System.exit(1);
}
}
}
```


----------------------------------------




```
// AppletClient.java

import java.awt.*;
import java.applet.*;
import java.net.*;
import java.io.*;

public class AppletClient extends Applet 
{
	TextArea textArea=new TextArea(6,60);

	public void init()
	{
	// Set arguments
	String host="localhost";
	int port=1234;
	// GUI layout
	setLayout(new BorderLayout());
	add(textArea);
	
	
		try
		{
		
		Socket server=null;
		while(true)
		{
			 
			try
			{
			server=new Socket(host,port);
			}
		catch(UnknownHostException ex)
			{
			System.err.println("Cannot find Host"+host);
			System.exit(1);
			}

		
		// Send some data over socket
		OutputStream out = server.getOutputStream();
		PrintWriter outputSocket= new PrintWriter(out,true);
		outputSocket.println("Hi Server, how are you?");
                textArea.append("Client sends the question\"Hi Server, how are you?\" to the Server.\n");
		// Readtheansweroversocket
		InputStream in = server.getInputStream();
		BufferedReader inputSocket= new BufferedReader(new InputStreamReader(in));
		String response= inputSocket.readLine();
		textArea.append("Server says: "+response+"\n");
		outputSocket.println();
		outputSocket.flush();
		inputSocket.close();
		outputSocket.close();
		

		}
		}
		catch(Exception ex)
		{
		System.err.println("Error in communication:");
		ex.printStackTrace();
		System.exit(1);
		}
	}
}
```

---------------------------------

*Mein Ziel ist es, damit ein Chat aufzubauen, aber bei der Ausführung bleibt er bei der ersten Anwort stehen.

Ich hoffe jemand kann mal kurz seine Profi-Augen über mein simples Proggie fliegen lassen und mir irgendwie helfen, das wäre echt Klasse, vielen Dank!

Gruß*


----------



## SlaterB (29. Nov 2006)

du schließt den System.in-Stream,
da kommt es bei mir gar zu einer Fehlermeldung, bei dir nicht?
auf jeden Fall kann man danach wohl nichts mehr eingeben auf Serverseite,

ob man die Streams/ Reader einfach offen lassen kann weiß ich im Moment nicht,
vielleicht machst du einfach nur einen BufferedReader um System.in, 
ebenso statisch wie System.in?

was passiert eigentlich, wenn sich mehrere Clients gleichzeitig melden und mehrere readLine() auf die Eingabe warten?   ???:L


----------



## pank13 (29. Nov 2006)

Hmm, für mich sieht es so aus als wenn der Serverthread nur einmal durchlaufen wird. Dann wird die Verbindung unterbrochen. Dann kann der Client erst wieder was schicken wenn er eine neue Verbindung hat. Vielleicht solltest Du in den Serverthread ( also in RUN() )eine Schleife mit Abbruchbed. "Client Verbindung abgebrochen" 
reinproggen..
Frank


----------



## hansch (30. Nov 2006)

Ich glaube dein Server erfüllt nicht ganz den von dir gewünschten Nutzen. Ausser du willst, dass jeweils Server und Client nur genau einaml etwas zu einander sagen und fertig.. von den Exceptions die geworfen werden wenn du so mehrere Clients behandeln musst mal abgesehen.
Ganz banal hast du zwei Möglichkeiten:

1. Thread für Eingang und Thread für Ausgang:

```
class Eingang extends Thread 
{
	Socket socket;
	
	Eingang(Socket s)
	{
		socket = s;
	}
	
	BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());

	...

	while (solangeIchLebe)
	{
		System.out.println("Nachricht vom Client: " + in.readLine());
	}
	
	...
}


class Ausgang extends Thread
{
	Socket socket;
	
	Ausgang(Socket s)
	{
		socket = s;
	}
	
	PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    BufferedReader shell = new BufferedReader(new InputStreamReader(System.in));

	...

	while (solangeIchLebe)
	{
		out.println(shell.readLine());
	}

	...
}
```

2. einen Thread für beides

```
class EingangAusgang extends Thread 
{
	Socket socket;
	
	EingangAusgang(Socket s)
	{
		socket = s;
	}
	
	BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());
	PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
    BufferedReader shell = new BufferedReader(new InputStreamReader(System.in));

	...

	while (solangeIchLebe)
	{
		if (in.ready())
			System.out.println("Nachricht vom Client: " + in.readLine());
		out.println(shell.readLine());
		sleep(250);
	}

	...
}
```

Exceptions und das Beenden der Verbindung hab ich mir jetzt mal gespart.

Also falls sich die 2 (oder mehr) Teilnehmer mehr zu sagen haben als nur eine Zeile, könntest du probieren den Code wie beschreiben umzubauen. Falls nicht, hab ich dich eben falsch verstanden 

Ach und wenn du einen PrintWriter mit der Option autoFlush = true erstellst, brauchst du den flush()-Befehl nicht extra noch aufzurufen.

lg


----------



## Guest (1. Dez 2006)

Vielen Dank, hansch, SlaterB, und pank13.

hansch und pank, ich habe ServerThread jetzt so geändert:


```
//ServerThread.java

import java.net.*;
import java.io.*;


public class ServerThread extends Thread {
private Socket client;
public ServerThread(Socket client) {
this.client = client;
} 

public void run()
{ 

try
{		
		InputStream eingehend = client.getInputStream();
		BufferedReader SocketRein=new BufferedReader (new InputStreamReader(eingehend));
		OutputStream ausgehend=client.getOutputStream();
		PrintWriter SocketRaus=new PrintWriter (ausgehend,true);
		BufferedReader SocketEingabe=new BufferedReader(new InputStreamReader(System.in));
		String NachrichtRaus="A";

		while(NachrichtRaus!=null)
		{
		if (SocketRein.ready())
			{	
			String NachrichtRein=SocketRein.readLine();
			System.out.println("Client sagt: "+NachrichtRein+"\n");
			}

		System.out.println("Was möchten sie dem Mitarbeiter sagen?\n");
		NachrichtRaus=SocketEingabe.readLine();
		SocketRaus.println(NachrichtRaus);
		System.out.println("Der Server sendet folgende Nachricht zum Mitarbeiter: \n"+NachrichtRaus);
		sleep(250);
		}

		SocketEingabe.close();
		SocketRaus.close();
		client.close();
}
catch(Exception ex)
{
	System.err.println("Es ist ein Kommunikationsfehler aufgetreten. Das System meldet:\n"+ex+"\n");
	ex.printStackTrace();
	System.exit(1);
}
}
}
```

Das sieht für mich auch schlüssig aus.Er bleibt jetzt auch nicht mehr hängen, nur das Zusammenspiel mit dem AppletClient läuft nicht, es ist irgendwie recht chaotisch, ich komm nicht dahinter. Ich habe ja eine client.html, die den oben angegebene AppletClient aufruft mit dem simplen Inhalt:


```
<APPLET CODE="AppletClient.class"
	WIDTH=500
	HEIGHT=200
>
Ihr Browser kann keine Applets darstellen
</APPLET>
```

Aber der AppletClient denkt gar nicht daran eine Textarea zu adden oder sonst irgendwas zu tun.

Das mit dem doppelten flushen hab ich übrigens entfernt.   

SlaterB, bei mir kommt es zu keiner Fehlermeldung. Wie meinst Du das denn mit System.in? 
Ich habe es noch nicht probiert mit mehreren Clients, ich dachte ich versuchs ersmal mit einem...

Danke und Grüße


----------



## Tahomar (1. Dez 2006)

Oh, hab meinen Namen gar nicht genannt, also obiges Post ist von mir...

Viele Grüße, Tahomar


----------



## hansch (1. Dez 2006)

Ops, hab da auch was verbock   


```
while (solangeIchLebe)
   {
      if (in.ready())
         System.out.println("Nachricht vom Client: " + in.readLine());
      out.println(shell.readLine());
      sleep(250);
   }
```

... ist auch nicht wirklich sinnig, da System.in die Schleife blockiert.
Es sollte wohl eher so sein:


```
while (solangeIchLebe)
   {
      if (in.ready())
         System.out.println("Nachricht vom Client: " + in.readLine());
      if (shell.ready())
         out.println(shell.readLine());
      sleep(250);
   }
```

Die Idee ist die, dass die Schleife checkt ob am Stream-Eingang und am System.in eine Nachricht wartet und sie ggf. ausgiebt bzw weiterleitet. Die Schleife läuft solange solangeIchLebe wahr ist und wird alle 250ms + Abarbeitsdauer durchgeführt.

Solltest du jetzt deinen Code entsprechend umbauen, überlege dir, wie du die Nachrichten anlegst, sonst wird der Server 4x di Sekunde mit "Was möchten Sie..." zugespammt 


Zum Client
Wenn du nicht willst, dass di GUI einfriert, lass die Kommunikation einen Thread behandeln. Hab da mal schnell etwas zusammengesponnen.. hoff es stimmt diesesmal  :roll: Statt Runnable kannst du natürlich auch wie oben Thread erweitern.


```
class MyApplet extends Applet
{
	...
	
	BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream());
	
	Thread portier = new Thread (new Portier(in));

	...
	
	class Portier implements Runnable
	{
		BufferedReader in;
		
		public Portier(BufferedReader in)
		{
			this.in = in;
			this.start();
		}
		
		public void run()
		{
			...
			

            while (solangeIchLebe)
            {
	            textArea.append(in.readLine());
           	}
           	
			...
		}			
	}
}
```

Will dein Client dann noch Nachrichten versenden, füge die entsprechendne GUI-Elemente hinzu und Verpasse dem Button oder Textfeld eien Listener, der die Nachricht in den Ausgangs-Stream schreibt.
lg


----------



## Tahomar (3. Dez 2006)

Ok, hab die erste Änderung durchgeführt, aber mit Deinem zweiten Vorschlag weiß ich nicht so recht was ich damit in Verbindung mit meinem Programm machen soll...

Viele Grüße


----------

