# Inputstream.read()/readLine() blockiert immer



## Uhm (9. Mai 2009)

Meine Frage kurz formuliert:
Wie überprüfe ich ob im Inputstream etwas Neues drinnen ist, damit ich dann .read() im gegenteiligen Fall überspringen kann?

Lang:
Also ich seh im Moment keinen Ausweg: In zb. einem Chat muss ich doch pro Frame einmal nachsehen was im Inputstream geliefert wurde, und das dann auslesen. Nur wird natürlich nicht 1mal pro Frame etwas geliefert, also hängt alles - was völlig inakzeptabel ist. 
Jetzt hab ich die Methode availabe() gefunden die mir die Anzahl der Bytes liefern soll, die ich bis zum nächsten Blockieren ungefährdet lesen kann. Aber in der Doku steht:
_"The available method for class InputStream always returns 0. 
This method should be overridden by subclasses. "_
Subklassen wie BufferedReader oder InputStreamReader haben aber keine available() Methode. Sagt jetzt bloß nicht dass ich mir selbst einen Reader schreiben muss!

Achja, außerdem dreht mein PC irre auf wenn das Programm gestartet wird, ich hab aber keine rechenintensiven Tasks...das ist auch vom Blockieren nehm ich an oder?


----------



## Schandro (9. Mai 2009)

> Subklassen wie BufferedReader oder InputStreamReader haben aber keine available() Methode.


^^ wenn sie Subklassen von InputStream sind erben sie doch alle Methoden von InputStream, also auch aviable().
Es kann höchstens sein das sie es auch nicht richtig überschreiben.

Für den Rest müsstest du ein bisschen Code posten.


----------



## Uhm (9. Mai 2009)

Du hast recht, meine Streambeispiele waren gar keine Unterklassen. Aber selbst in den Unterklassen steht in available nur: 
_"This method simply performs in.read() and returns the result." _
Was im Endeffekt wieder nicht die gewünschte Funktionalität bietet...


```
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
OutputStream os = cs.getOutputStream();
String line = br.readLine(); <--blockiert eeeewig da auf dem anderen PC ebenfalls read() aufgerufen werden muss und ewig blockiert. Das soll einfach übersprungen werden wenn nichts drinnen ist!
```


----------



## Schandro (9. Mai 2009)

starte doch einfach einen eigenen Thread, der immer in.read() aufruft und jedesmal, wenn irgendein Signal geschickt wird, das die aktuelle Nachricht zuende ist, es an irgendwas weiterleitet und dann weiter in.read() aufruft.


----------



## Uhm (9. Mai 2009)

Ahh, einen eigenen Thread extra nur für eine Methode praktisch? Ist es gängig sowas zu machen? Wie man merkt bin ich ein Anfänger, deswegen frag ich 
Klingt auf jeden Fall sehr gut, danke. Dann gibt mir der Thread praktisch ständig meine Werte zurück, und wenn null/-1/ungültig zurückkommt, beachte ich das einfach nicht. Sooo.. jetzt mal rein ins Vergnügen.


----------



## Noctarius (9. Mai 2009)

Oft wenn es um Streams geht ist es ratsam solche Dinge auszulagern (außer du willst nur eben eine Datei lesen oder schreiben).
An manchen Punkten bist du sogar gezwugen es so zu machen (Fernsteuern von Konsolenanwendungen mit Input-, Output- und Errorstream).

Ich würde auch sagen, pack es mal in einen eigenen Thread und benutz das Observer-Pattern um Daten an einen verarbeiteten Thread weiterzureichen.


----------



## musiKk (9. Mai 2009)

Uhm hat gesagt.:


> und wenn null/-1/ungültig zurückkommt, beachte ich das einfach nicht.



Wenn null (readLine) oder -1 (read) zurückkommt, solltest Du das schon beachten, da ist der Stream nämlich zu.


----------



## Uhm (9. Mai 2009)

Also die Sache funktioniert überhaupt nicht. Der Chat läuft schon so langsam dass mein PC sich aufhängt (wegen der while(true) schleifen glaub ich, aber ich bekomme nach ner Weile out of heap memory Errors), und Strings werden zwar übertragen, aber nur wenn ich mit dem Debugger Thread für Thread abwechselnd durchlaufe. Die pfuschen sich irgendwie gegenseitig rein. Werden Bytes denn nicht im OutputStream gehalten solange bis ich sie rauslese? Ich stell euch die run() Methoden rein, vielleicht seht ihr nen offensichtlichen Fehler...mann, bei solchen Dingen hinterfrage ich immer ob Programmieren wirklich was für mich ist :/

```
/* **SERVER** run() method of the ConnectionManager class, which holds all currently connected sockets.*/
while(true)
		{
/* This loops through all sockets in "connectionList" and all threads in "readers" 
and reads and writes string data from the GUI into/from their streams.*/

			for (int i = 0; i < connectionList.size(); ++i)
			try 
			{ 
				Socket cs = connectionList.get(i); 
				
				OutputStream os = cs.getOutputStream();
				
				String line = readers.get(i).getString();
				if (line != null && !line.equals(""))
				{
					byte[] tempBytes = line.getBytes();
					for (int j = 0,counter = i; j < connectionList.size(); ++j,counter=(counter+1)%connectionList.size())
					{// write the data from one client, to all the other clients
						os.write(tempBytes);
					}
					app.appendString(line); // +display them on server
				}
			
			}
```


```
**CLIENT**

while(running)
		{
			// get string data from the application
			String temp = app.getSentText();
			
			if (!temp.equals("\n") && !temp.equals(""))
			try {
				byte[] buffer = temp.getBytes();
				os.write(buffer, 0, buffer.length);
				
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			// receive server data and write to client GUI
			String line = reader.getString();
			if (line != null && !line.equals("") && !line.equals("\n"))
			{
				this.app.appendString(line);
			}
			
			
		}
```

Eure vorgeschlagene Readerklasse. Jeder Socket hat so einen Readerthread, der ewig läuft und ständig vom Inputstream nachliest.

```
public class ReaderThread implements Runnable {

	private Socket sc;
	private String readString;
	public ReaderThread(Socket socket)
	{
		this.sc = socket;
		readString = new String();
	}
	public void run() 
	{
		while (true)
		{
			InputStream is;
			try {
				is = sc.getInputStream();
				InputStreamReader isr = new InputStreamReader(is);
				BufferedReader br = new BufferedReader(isr);
				readString += br.readLine();
	
			} catch (IOException e) {
				e.printStackTrace();
			}	
		}
		
	}
	public String getString()
	{// return everything that has been read, and reset the "buffer" string to zero characters
		String temp = readString;
		readString = new String();
		return temp;
	}
	
}
```


----------



## Schandro (9. Mai 2009)

> new String()


Es ist (imho) nie sinnvoll das aufzurufen, wenn du einen "leeren" string haben willst, schreib einfach nur
""



> readString += br.readLine();


Strings mit dem plus Operator aneinanderzuhängen ist extrem, *wirklich *extrem Performancefressend sobald es in Schleifen passiert.
€dit: Mach aus readString einen StringBuffer (nicht StringBuilder) und benutz die .append Methode zum dranhängen. StringBuffer ist threadsafe.


Schreib die Zeilen 16 bis 18 außerhalb der unendlichschleife, ansonsten initialisierst du für jede einzelne Zeile die gelesen werden soll immer extra einen neuen BufferedReader und InputStreamReader....


----------



## sparrow (9. Mai 2009)

Die innere for-Schleife auf dem Server versteh ich nicht.


----------



## Uhm (9. Mai 2009)

Hab deine Verbesserungen eingebaut, hab aber noch immer 100% Prozessorauslastung. Dafür scheint kein heap overflow mehr zu kommen. Ich kann mir vorstellen warum ich 100% habe, immerhin versucht der Prozessor eine while(true) Schleife sooft wie möglich aufzurufen. Sooft wie möglich ist nunmal immer 100%... gibts eine Alternative zu while(true) und trotzdem einen ständig im Hintergrund laufenden Thread zu haben? 
@sparrow:
Die innere for-Schleife fängt bei dem aktuellen Socket an und iteriert solange (auch über das Ende der Liste, deswegen die Modulooperation) bis alle Clients/Sockets einmal angeschrieben wurden mit dem neuen String.
Zb.: 
Socket an der Stelle 3 ist aktuell. Liste hat 5 Mitglieder. Dann schicke ich zuerst den String an Socket3, dann 4, 5, dann 1,2 und aus. Insgesamt schicke ich 5 mal. Bisschen allgemeiner gesagt: ich schicke solange bis "j" 5 erreicht hat.


----------



## sparrow (9. Mai 2009)

Welcher Thread bringt die Auslastung?
Der Server, richtig?


----------



## Uhm (9. Mai 2009)

Nein, beide gleich. Anscheinend ist es ein Problem in der GUI, sonst gibts ja keine andere Erklärung. Hab bemerkt dass schon bevor ich den geringsten Netzwerkcode starte, es auf 100% springt. Glaub echt dass die while() Schleifen das Problem sind, denkt ihr nicht? Hier ist wie ich das ganze aufziehe: 

```
**MAIN Methode**
// the user has to define port, host and application type before continuing
GUI app = new GUI();
new Thread(app).start();
while (!app.isInitialized());
if (app.applicationType.equals("Server")
{
. . .
}else
...
```


```
**ein paar relevante GUI Methoden: **
public void run() 
{
		createAndShowGUI(); // create labels, buttons, frames..
		while (true);
}
public void actionPerformed(ActionEvent arg0) 
{
if (arg0.getActionCommand() == "enter")
		{
			sentMessage = textField.getText();
			textField.setText("");
		}
}
public String getSentText()
	{
		// clear it, so we dont send one message possibly twice
		String temp = sentMessage + "\n";
		sentMessage = "";
		return temp;
	}
	public void appendString(String append)
	{
		textareaText = append;
		textArea.append(textareaText + "\n");
	}
```

Übrigens kann ich denk ich, bestätigen dass die Threads sich gegenseitig stören. Ich hab testweise den übertragenen String nie gelöscht, und einfach immer wieder dranhängen lassen (mit append)...und siehe da: das ganze Fenster war in nem Bruchteil einer Sekunde voll mit meinem Testwort. Nur versteh ich nicht wie sie sich stören können, immerhin wird korrekt in den Outputstream reingeschrieben, das hab ich überprüft.
ajo und in der inneren for Schleife fehlt 
	
	
	
	





```
os = connectionList.get(counter).getOutputStream();
```


----------



## sparrow (9. Mai 2009)

Moment, also erstmal:
jede while-Schleife die ungebremst durchläuft verbraucht immer alle Resourcen, da ja nie eine Pause eingelegt wird. Selbst wenn die Schleife leer ist würden alle Resourcen dafür aufgebraucht werden die leere Schleife immer wieder zu durchlaufen.

Ich würde auf dem Server wie folgt vorgehen:

Klasse 1 -> Initialisiert ggf. die GUI und initialisiert und die Sockets aufbaust
Sockets werden, wie du es schon hast, in einer Collection verwaltet. Ich würde hier auf eine HashMap setzen mit dem Benutzernamen als Key. So könnte man auch mal flüstern weil man einfach an den Benutzernamen kommt.
Das wo die Sockets lauschen sollten jeweils einzelne Threads sein. Die verbrauchen ja eben nicht die vielen Resourcen weil sie blockieren bis etwas herein kommt.

So, und dann eben nicht einen Thread immer durchlaufen lassen, sondern eingehende Nachrichten in einer Collection speichern und einen "sendeThread" immer schlafen lassen und bei einer eingehenden Nachricht aufwecken.
Dieser durchsucht dann die Colection mit den Nachrichten und sendet alle verfügbaren Nachrichten an alle Adressaten.


----------



## Uhm (10. Mai 2009)

Also warum ich einen extra Sendethread brauche, ist mir nicht klar. Die Nachrichten mal eben in den Outputstream zu schreiben dauert ja nicht lange, und wird sowieso per Knopfdruck, (also bei Druck auf Enter im Textfeld) gemacht bzw. gleich nachdem etwas eingelesen werden konnte.
Und while(true) schleifen brauch ich trotzdem fürs Einlesen von Daten, ein Thread hat ja keinen Rückgabewert. Deswegen muss ich ständig 1mal pro Frame überprüfen ob der Lesethread gerade etwas gelesen hat oder nicht. => resultiert wieder in 100% CPU


----------



## sparrow (10. Mai 2009)

Uhm;515892Deswegen muss ich ständig 1mal pro Frame überprüfen ob der Lesethread gerade etwas gelesen hat oder nicht. => resultiert wieder in 100% CPU :([/QUOTE hat gesagt.:
			
		

> Wieso pro Frame? Programmierst du ein Spiel?
> Falls nicht, und du eine SWING-Oberfläche hast, brauchst du nicht jede Sekunde nachschauen.
> Wenn du z.B. eine bufferedReader mit .readLine() verwendest blockiert der Thread doch sowieso so lange bis eine vollständige Line vorliegt. Demnach ist es einfacher und schonender für die Resourcen wenn nach einer komplett empfangenen Line dafür sorgt, dass andere Programmteile darüber informiert werden (notice) anstatt ständig zu fragen (polling) ob eventuell neue Informationen vorliegen.


----------



## ModellbahnerTT (10. Mai 2009)

Völlig falsches vorgehen, schau in die FAQ, da ist ein Beispiel für einen Chat, oder denkst du wirklich es ist sinnvoll ununterbrochen zu schauen ob der benutzer was in das textfeld eingibt und das zu senden (dass dann 100x mal das selbe gesendet wird ist dir nicht in den Sinn gekommen?) anstatt auf Befehl (knopf/enter gedrückt) EIN mal den text aus dem feld zu senden?


----------



## Uhm (10. Mai 2009)

> oder denkst du wirklich es ist sinnvoll ununterbrochen zu schauen ob der benutzer was in das textfeld eingibt und das zu senden


Einfacher zu programmieren wärs auf jeden Fall, ich nehm an dass man noch irgendwie mit nem Timer einstellen könnte dass nur jede 0.5 Sekunden nachgeschaut werden soll.

Danke Leute, ich hab es dank eurer Hilfe doch tatsächlich noch zum Laufen gebracht. Das Problem was ich jetzt habe ist "nur", dass wenn sich ein Client rausklingt, sich alles aufhängt weil "Connection reset" Exceptions ohne Ende gerufen werden.
Ich kapier nur nicht wo genau das Problem des Programms jetzt ist. Es soll einfach weitermachen ohne diesen Socket. (dazu muss ich jetzt sagen dass ich von Exceptions wenig Ahnung habe... ich weiß nur dass man irgendwie abfangen kann, aber ich klick immer nur auf "generate try and catch" :autsch



> java.net.SocketException: Connection reset
> at java.net.SocketInputStream.read(Unknown Source)
> at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
> at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
> ...


----------



## sparrow (10. Mai 2009)

*seufz*

Und genau das ist das Problem.
Du klickst "einfach nur auf generate xy".

Wie man des öfteren liest lernt man Programmieren nur durch Programmieren. Den Syntax und die Basics (und die Verwendung von Exceptions sind Java-Basics) lernt man nur durch eine einzige Sache: lesen!
www.javabuch.de - Das Handbuch der Java-Programmierung


----------

