# ObjectInputStream EOF



## Kar (6. Dez 2011)

Hallo,

ich möchte mir einen kleinen Chat basteln aber bei der Übertragung fängt schon das Problem an.
Hier ersteinmal die Source-Dateien:

Server.java:

```
package chat.server;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class Server {
	private ServerSocket serverSocket;
	private ArrayList<Socket> clients;
	
	public Server(int port) {
		try {
			this.serverSocket = new ServerSocket(port);
		} catch (IOException e) {
			e.printStackTrace();
		}
		System.out.println("Server wurde gestartet!");
		clients = new ArrayList<Socket>();
		ServerAcceptor acceptor = new ServerAcceptor(this);
		acceptor.start();
	}
	
	public ServerSocket getServerSocket() {
		return this.serverSocket;
	}
	
	public ArrayList<Socket> getClients() {
		return this.clients;
	}
	
	public static void main(String[] args) {
		new Server(1205);
	}
}
```

ServerAcceptor.java

```
package chat.server;

import java.io.IOException;
import java.net.Socket;

public class ServerAcceptor extends Thread {
	private Server server;
	
	public ServerAcceptor(Server server) {
		this.server = server;
	}
	
	@Override
	public void start() {
		super.start();
		System.out.println("ServerAcceptor wurde gestartet und wartet auf Anmeldungen!");
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				Socket clientSocket = server.getServerSocket().accept();
				server.getClients().add(clientSocket);
				new ServerReader(clientSocket);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
}
```

ServerReader.java

```
package chat.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;

public class ServerReader extends Thread {
	private static int INST = 0;
	private Socket client;
	
	public ServerReader(Socket client) {
		INST++;
		this.client = client;
		this.start();
	}
	
	@Override
	public void start() {
		super.start();
		System.out.println("ServerReader: " + INST);
	}
	
	@Override
	public void run() {
		ServerActionController ctrl = ServerActionController.getInstance();
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(client.getInputStream());
		} catch (IOException e) {
			e.printStackTrace();
		}
		while(true) {
			try {
				Object obj = ois.readObject();
				ctrl.doAction(client, obj);
			} catch(IOException e) {
				e.printStackTrace();
				//System.exit(0);
			} catch(ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
}
```

ServerActionController.java

```
package chat.server;

import java.net.Socket;

import chat.objects.Message;

public final class ServerActionController {
	private static final ServerActionController INSTANCE = new ServerActionController();
	
	private ServerActionController() {}
	
	public static ServerActionController getInstance() {
		return INSTANCE;
	}
	
	public void doAction(Socket sender, Object obj) {
		if(obj instanceof Message) {
			Message msg = (Message) obj;
			System.out.println("-------------------");
			System.out.println(sender.getInetAddress().toString() + ":");
			System.out.println(msg.getMessage());
			System.out.println("-------------------");
		}
	}
}
```

Der wichtige Teil des Clients:

```
socket = new Socket("127.0.0.1", 1205);
oos = new ObjectOutputStream(socket.getOutputStream());
Message msg = new Message("Test");
oos.writeObject(msg);
```

Die Ausgabe sieht wie folgt aus:

```
Server wurde gestartet!
ServerAcceptor wurde gestartet und wartet auf Anmeldungen!
ServerReader: 1
-------------------
/127.0.0.1:
Test
-------------------
java.io.EOFException
	at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at chat.server.ServerReader.run(ServerReader.java:37)
```
Nachdem ein Objekt übertragen wurde, wird in der ServerReader Klasse andauernd EOFExceptions geworfen. Blockiert readObject() nicht, bis etwas da ist, was gelesen werden kann? Wie kann ich das Werfen der Exceptions verhindern?

Ich bedanke mich für jede Antwort.

Gruß


----------



## SlaterB (6. Dez 2011)

da schreibst du soviel vom Server, aber nur 4 Zeilen vom Client?
grundsätzlich gilt die Regel dass die EOFException genau auch beim Ende des Streams kommt,
da der Server wahrscheinlich gerade nichts schlimmes macht wird der Client entweder den Socket geschlossen 
oder irgendwie schlecht mit dem  ObjectOutputStream umgegangen haben so dass der jedenfalls zu ist

> Blockiert readObject() nicht, bis etwas da ist, was gelesen werden kann?
falls übersehen: ein oder mehrere Objekte können durchaus erfolgreich gelesen sein worden,
die Schleife geht danach direkt wieder ins Lesen und dann kommt die Exception

mit den Ausgaben in ServerActionController allerdings vielleicht nicht zu übersehen


----------



## Kar (6. Dez 2011)

Danke für deine Antwort.
Der Client besteht bisher nur aus einer kleinen Testklasse, in der eine Verbindung zum Server aufgebaut, ein Objekt gesendet  und anschließend alles geschlossen wird.


```
package chat.client;

import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import chat.objects.Message;


public class Client {

	public Client() {
		Socket socket = null;
		ObjectOutputStream oos = null;
		try {
			socket = new Socket("127.0.0.1", 1205);
			oos = new ObjectOutputStream(socket.getOutputStream());
			Message msg = new Message("Test");
			oos.writeObject(msg);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
				oos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	public static void main(String[] args) {
		new Client();
	}
}
```

Liegt es also daran, dass ich clientseitig die Verbindung einfach abbreche, ohne den Server vorher darüber zu informieren?


----------



## SlaterB (6. Dez 2011)

der Client muss nicht unbedingt informieren, ohne Timeout-Konfiguration wird es beim Server eh schwer, das read() abzubrechen,
siehe die Exception hier nicht als Problem sondern als Steuerung an und reagiere darauf entsprechend,
im Moment wird weiter gelesen, Endlosschleife, bei EOFException oder vielleicht bei allen ist zumindest Ende der while-true-Schleife zu überlegen,

die erste Test-Nachricht wird auch vor der Exception erfolgreich übertragen, habe es gerade getestet,

edit:
ein Ende-Objekt zu senden ist natürlich relativ elegant, 
dann kann ganz normal aus der Schleife gesprungen werden


----------



## Kar (6. Dez 2011)

SlaterB hat gesagt.:


> der Client muss nicht unbedingt informieren, ohne Timeout-Konfiguration wird
> edit:
> ein Ende-Objekt zu senden ist natürlich relativ elegant,
> dann kann ganz normal aus der Schleife gesprungen werden


So habe ich es jetzt gemacht, funktioniert super. Vielen Dank nochmal.


----------



## hansmaulwurfsim (14. Dez 2011)

Habe gerade durch Google diesen Thread gefunden und hätte ziemlich genau dazu noch eine Frage:

Wenn man bei einem DataInputStream readUTF() verwendet, bleibt mein Thread ja jedes Mal stehen und wartet, bis was kommt -> kein busy waiting

Genau das will ich jetzt auch mit einem ObjectInputStream erreichen. Da ich nicht weiß, wann genau ein Objekt kommt, soll der Thread einfach hören und wenn ein Objekt kommt, das Ganze behandeln.
Da readObject() aber anscheinend null oder eof zurückgibt, falls kein Objekt ankommt stehe ich vor einem Problem. 
Natürlich könnte ich das abfangen und die Schleife neu starten, dann hätte ich aber busy waiting und das ist ja wohl nicht Sinn der Sache.

Hat jemand eine Idee, wie man das lösen könnte?

Danke


----------



## SlaterB (14. Dez 2011)

Busy waiting funktioniert genauso,
null wird höchstens dann gelesen wenn auch null drinsteht, EOF kommt eben beim Ende des Streams,
solange der Stream offen ist gibt es auch keine Probleme, anderenfalls versagt jeder Stream auf gleiche Weise


----------

