# Brauche hilfe bei Projekt: Netzwerk Chatprogramm



## jagdfalke (7. Jan 2006)

Hi,
ich hab mir mittlerweile mal die Grundlagen der Netzwerkprogrammierung angeeignet und bin gerade dabei in kleines Programm zu schreiben, dass das chatten innerhalb eines Netzwerks (192.168.2.1 bis 192.168.2.254) ermöglicht. Ich mach mal ne kleine beschreibung von dem was ich bis jetzt geschrieben habe:

Zum Server-Teil:
Jeder Rechner lässt einen Server laufen, der per Thread in der Klasse "Server", wenn eine Connection eintrifft, ein ServerConnection-Objekt erzeugt und es in einen Vector hinzufügt. Dieser Vector ist in der Klasse "Server". In der Klasse "ServerConnection" wird dann dir Kommunikation geregelt aber so weit bin ich noch nicht.
An dem Server in ein ServerListener registriert, der von der GUI-Klasse implementiert wird, um in einer JList und einem JLabel den Status des Servers anzeigen zu können.

Server.java hat folgende Methoden: (extends Thread)

public void run();
public void startServer();
public void shutdown();
public int getConnectionCount();
public boolean isOnline();
public void addServerListener();

und einige fireXXXEvent()-Methoden.


Zum Client-Teil:
Auf der GUI kann man eine IP und einen Port eingeben und auf "Connect" klicken, dann wie an die Klasse "Client" die aufforderung gesendet dort hin eine Verbindung aufzubauen, falls nicht schon eine zu dieser Adresse existiert. "Client" speichert vorhandene Verbindungen in Form eines "ClientConnection"-Objekts in einem Vector.
Bald soll man dann der Klasse Client sagen können, sie soll an die IP xxx.xxx.xxx.xxx die Message y senden. Aber das ist noch Zukunft.



Zur GUI:
Die GUI ist relativ uninteressant, da Einzige: 

```
this.addWindowListener(new WindowAdapter() {
										public void windowClosing(WindowEvent ev) {
											srv.shutdown();
											client.shutdown();
											dispose();
											System.exit(0);
										}
									});
```
Beim Schließen des Fensters wird der Server und der Client "heruntergefahren" und alles Connections beendet.



Jetzt zu meinen Fragen:

1) Wie kann ich im Server bzw im Client überwachen lassen, ob eine Verbindung noch besteht, damit die Vektoren aktualisiert werden können?

2) Beim Schließen des Fensters kommt unendlich oft hintereinander
"Server sayed: null" in der Konsole. Das kommt aus der Klasse ClientConnection, deren run-Methode so aussieht:

```
public void run() {
		while(!isInterrupted()) {
			try {
				String input = this.in.readLine();
				System.out.println("Server sayed: " + input);
			} catch(Exception ex) {
				this.interrupt();
			}
		}
	}
```
Wie kommt das? Wenn "client.shutdown()" ausgeführt wird passiert das hier:

```
private Vector<ClientConnection> connections = new Vector<ClientConnection>();
        ...
        ...
	public void shutdown() {
		for(int i=0; i<=connections.size()-1; i++) {
			connections.get(i).close();
		}
		connections.clear();
	}
```
Die close()-Methode aus der Klasse "ClientConnection" sieht so aus:

```
public void close() {
		this.interrupt();  //ClientConnection ist auch ein Thread (Der "Gegen-Part" von "ServerConnection")
		try {
			this.socket.close();
		} catch(Exception ex) {}
	}
```



Falls das nicht reicht um das Problem zu lösen: Hier die Klassen des Servers und des Clients:
(Die Listener-Klassen lass ich weg, sowie die GUI-Klasse)

Server.java

```
package server;

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

public class Server extends Thread{

	private ServerSocket sckServer;
	private Vector<ServerConnection> connections = new Vector<ServerConnection>();
	private Vector<ServerListener> listener = new Vector<ServerListener>();

	public void run() {
		int cnt = 0;
		while(!this.isInterrupted()){
			try {
				//KEEP ACCEPTING CONNECTIONS AND ADD THEM TO VECTOR connections
				Socket sck = sckServer.accept();
				ServerConnection con = new ServerConnection(cnt, sck);
				connections.add(con);
				cnt++;
				this.fireClientConnectedEvent(con);
			} catch(Exception ex) {}
		}	
	}
	
	public void startServer() {
		try {
			sckServer = new ServerSocket(12345);
			this.start();
			this.fireServerStartedEvent();
		} catch(IOException ex) {
			ex.printStackTrace();
		}
	}
	public void shutdown() {
		try {
			this.interrupt();
			sckServer.close();
		} catch(Exception ex) { /*IGNORE*/ }
		for(int i=connections.size()-1; i>=0; i--) {
			connections.get(i).interrupt();
			connections.get(i).close();
			connections.remove(i);
		}
		this.fireServerShutdownEvent();
	}
	public int getConnectionCount() {
		return connections.size();
	}
	public boolean isOnline() {
		return !sckServer.isClosed();
	}

	public void addServerListener(ServerListener l) {
		if(!listener.contains(l)) {
			listener.add(l);
		}
	}
	
	private void fireClientConnectedEvent(ServerConnection th) {
		for(int i=0; i<=listener.size()-1; i++) {
			ServerListener l = (ServerListener)listener.get(i);
			ServerEvent ev = new ServerEvent(this, ServerEvent.CLIENT_CONNECTED);
			ev.setConnectionThread(th);
			l.clientConnected(ev);
		}
	}
	private void fireClientDisconnectedEvent() {
		for(int i=0; i<=listener.size()-1; i++) {
			ServerListener l = (ServerListener)listener.get(i);
			ServerEvent ev = new ServerEvent(this, ServerEvent.CLIENT_DISCONNECTED);
			l.clientDisconnected(ev);
		}
	}
	private void fireServerStartedEvent() {
		for(int i=0; i<=listener.size()-1; i++) {
			ServerListener l = (ServerListener)listener.get(i);
			ServerEvent ev = new ServerEvent(this, ServerEvent.SERVER_STARTED);
			l.serverStarted(ev);
		}
	}
	private void fireServerShutdownEvent() {
		for(int i=0; i<=listener.size()-1; i++) {
			ServerListener l = (ServerListener)listener.get(i);
			ServerEvent ev = new ServerEvent(this, ServerEvent.SERVER_SHUTDOWN);
			l.serverShutdown(ev);
		}
	}
}
```

ServerConnection.java

```
package server;

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

public class ServerConnection extends Thread{

	private Socket sckClient;
	private int index;
	private String ip;
	private PrintWriter out;
	private BufferedReader in;
	private String nick;
	
	
	public ServerConnection(int index, Socket socket) throws Exception {
		this.index = index;
		this.sckClient = socket;
		this.ip = sckClient.getInetAddress().getHostAddress();
		
		this.out = new PrintWriter(sckClient.getOutputStream());
		this.in = new BufferedReader(new InputStreamReader(sckClient.getInputStream()));
				
		this.start();
		
	}
	
	public void run() {
		while(!isInterrupted()) {
			try {
				String input = this.in.readLine();
				System.out.println("Client said: " + input);
				
			} catch(Exception ex) {
				this.interrupt();
			}
		}
	}
	
	
	public int getIndex() {
		return this.index;
	}
	public String getIP() {
		return this.ip;
	}
	public void close() {
		try {
			sckClient.close();
		} catch(Exception ex) { /*ignore*/ }
	}
	public boolean isConnected() {
		return sckClient.isConnected();
	}

}
```


Client.java

```
package client;

import java.util.Vector;

public class Client {

	private Vector<ClientConnection> connections = new Vector<ClientConnection>();
	
	public Client() {
		
	}
	
	public void connectTo(String ip, int port) throws Exception {
		if(!connectedToIP(ip)) {
			ClientConnection con = new ClientConnection(ip, port);
			connections.add(con);
			System.out.println("connection added");
		} else {
			System.out.println("allready connected to " + ip);
		}
	}
	
	private boolean connectedToIP(String ip) {
		for(int i=0; i<=connections.size()-1; i++) {
			if(connections.get(i).getIP().equals(ip)) {
				return true;
			}
		}
		return false;
	}
	
	public int getConnectionCount() {
		return connections.size();
	}
	
	public void shutdown() {
		for(int i=0; i<=connections.size()-1; i++) {
			connections.get(i).close();
		}
		connections.clear();
	}
	
}
```

ClientConnection.java

```
package client;

import java.net.Socket;
import java.net.UnknownHostException;
import java.io.PrintWriter;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class ClientConnection extends Thread{

	private String ip;
	private int port;
	private Socket socket;
	private PrintWriter out;
	private BufferedReader in;
		
	public ClientConnection(String ip, int port) throws UnknownHostException, IOException {
		this.ip = ip;
		this.port = port;
		this.socket = new Socket(ip, port);
		
		this.out = new PrintWriter(socket.getOutputStream());
		this.in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
				
		this.start();
	}

	public String getIP() {
		return ip;
	}
	public void sendMessage(String text) {
		this.out.println("<message>" + text);
		this.out.flush();
	}
	public void close() {
		this.interrupt();
		try {
			this.socket.close();
		} catch(Exception ex) {}
	}
	
	public void run() {
		while(!isInterrupted()) {
			try {
				String input = this.in.readLine();
				System.out.println("Server said: " + input);
			} catch(Exception ex) {
				this.interrupt();
			}
		}
	}
	
}
```


Ich hoffe irgendwer kann mir helfen. Wenn ihr das so auch nicht hinbekommt, meldet euch irgendwie, dann kann ich euch das komplette Projekt als .zip-File zuschicken.

mfg
jagdfalke


----------



## Campino (7. Jan 2006)

also: gegen das "server said: (buh pfui is das mit "sayed"): null" hilft folgenes: 
Teste input gegen null, also: 

```
if(input==null){
   //Server is weg, d.h. du kannst den Vector aktualisieren...die connection closen oder was immer du machen willst...
}
```


----------



## jagdfalke (7. Jan 2006)

ouch, das tut echt weh so ein Fehler  Und sowas ist im LK Englisch  (habs mal editiert)

Ja das stimmt schon, das würde helfen. Aber mich interessiert auch wie dieses null zustande kommt. Was macht der BufferedReader da eigentlich? Der blockiert doch den Thread oder? Aber hat der ein Timeout oder was?

mfg
jagdfalke


----------



## Campino (7. Jan 2006)

Der BufferedReader ließt eine Zeile (readLine()), wenn keine Zeile gesendet wird, ließt er null. Deine isInterrupted()-Methode gehört zu Thread, weil der Thread aner nicht weiß, dass er was mit dem Bufferedreader zu tun hat, läuft er wieter, wenn der Reader schon nichts mehr (eben null) liefert...

Normalerweise würde man:

```
BufferedReader br=nrew BufferedReader(...);
String line;
while((line=br.readLine)!=null){
    //mach was du willst, die gelesene Zeile ist in line...
}
```

verwenden. Die while()-Schleife wird automatisch verlassen, wenn der BufferedReader nichts mehr ließt.


----------



## Lim_Dul (7. Jan 2006)

btw, die Doku zu readLine sagt auch:


> Returns:
> A String containing the contents of the line, not including any line-termination characters, or *null if the end of the stream has been reached*


----------



## Campino (8. Jan 2006)

> Returns:
> A String containing the contents of the line, not including any line-termination characters, or *null if the end of the stream has been reached*


Noch einmal für den Englisch-LK:


> Rückgabewert:
> Ein String der den Inhalt der Zeile enthält, ohne Zeilenumbruchzeichen, oder null wenn das Ende des Streams erreicht ist.



Schlafmangel+Coca-Cola=Gute Laune

Gute Laune->Ich gehe allen auf die Nerven ;p


----------



## jagdfalke (8. Jan 2006)

Meine Fresse,  da macht man mal nen Fehler (und noch dazu nichtmal in Java) und schon wird man nurnoch gflamed 

Ok, mir war nur nicht klar, was "end of the stream" bedeutet. Ob nur die Übertragung vielleicht zu lange dauert oder was auch immer. Aber jetzt isses klar.

Thx
jagdfalke


----------



## Lim_Dul (8. Jan 2006)

Passiert 
Ich bin bei Sockets auch schon reingefallen, dass ich dachte, da kommt bestimmt eine IOException - Denkste 



> 1) Wie kann ich im Server bzw im Client überwachen lassen, ob eine Verbindung noch besteht, damit die Vektoren aktualisiert werden können?


Regelmässig einen Ping an die Clients senden. Beim Senden gibt es nämlich eine IOException, wenn die Verbindung nicht mehr aktiv ist


----------



## jagdfalke (8. Jan 2006)

Ich weiß jetzt nicht ob meine Methode "idiotensicher" ist haber ich habs jetzt so gemacht mit der Überwachung ob die Verbindung noch besteht: Ich lese vom BufferedReader und wenn null dabei raus kommt lasse ich den Socket schließen und ein Event feuern, damit auch alle nötigen Klassen darüber bescheid wissen.
Ist das so ok? Also beim Testen bis jetzt hats geklappt.

mfg
jagdfalke


----------



## Lim_Dul (8. Jan 2006)

Müsste auch funktionieren.


----------



## Campino (8. Jan 2006)

Lim_Dul hat gesagt.:
			
		

> Müsste auch funktionieren.



Was liefert der BufferedReader den, wenn nichts gesendet wird? Sperrt er dann den Thread? Sieht ja in der Schleifenvariante so aus...

jagdfalke:
für fehler in Java würde ich dich nicht flamen, da hätte ich hier ja nurnoch Feinde  :bae:


----------



## Lim_Dul (8. Jan 2006)

Wenn nichts gesendet wird, blockiert er solange, bis er eine komplette Zeile hat.


----------



## Campino (8. Jan 2006)

Lim_Dul hat gesagt.:
			
		

> Wenn nichts gesendet wird, blockiert er solange, bis er eine komplette Zeile hat.


Okay, dann gehts...


----------

