# InputStreamReader-> DataInputStream-> Socket.getInputS



## Neuling... (13. Apr 2008)

Hallo,
ich lerne noch nicht sehr lang Java, und bin daher noch nicht zu 100% mit dem Streamsystem vertraut.
Also:
Nachdem ein Socket geöffnet wurde, kann man ja mit getInputStream auf die Referenz von einem intern geöffneten InputStream zugreifen, mit dem man Daten von der Gegenseite empfangen kann! So, allerdings kenne ich schon das Problem von C++/Sockets. Versucht man zu lesen, obwohl noch nichts geschickt wurde, blockiert InputStream.read()...
Nun habe ich beim InputStreamReader die Funktion ready() gefunden, jedoch kann man ja einen InputStreamReader nicht mit einem DataInputStream koppeln, was ja bei Netzwerkprogrammen durchaus sinvoll wäre, und ich will bei java nicht erst eine Zahl in einen String umwandlen... Wie geht sowas ? Ist mein Vorhaben überhaupt durchführbar in Java ?
Bei C++/Sockets, gab es z.b. select() ...

Gruß Neuling


----------



## SlaterB (13. Apr 2008)

Socket liefert dir einen InputStream, nun gut,
beim InputStreamReader hast du ready() entdeckt, auch zu verstehen,

aber wo kommt in der ganzen Diskussion auf einmal ein DataInputStream her?
jedenfalls ist DataInputStream letztlich auch nur ein beliebiger InputStream,
und einem InputStreamReader kannst du einen InputStream als Parameter im Konstruktor übergeben,
geht also?


----------



## Neuling... (13. Apr 2008)

Ok, also vlt hab ich jetzt was flasches gelernt, aber ist es nicht so, dass der DataInputStream von InputStream abgeleitet ist, und der InputStreamReader eben von Reader. So, und ich wollte für die Übermittlung von Variablen übers Netzwerk eben DataOutput/InputStream nehmen. So und um nun auf der anderen Seite nach zuschauen, ob man überhaupt lesen kann, hab ich beim InputStream eine äquvivalente zu ready() gesucht, und nun auch gefunden, available()....
Ok, wenn ich es zu Umständlich gemacht hab bitte bescheid sagen!!


----------



## SlaterB (13. Apr 2008)

ich vertraue generell available() und ready() nicht besonders,
ansonsten bin ich aus deinen Erklärungen noch nicht schlauer geworden,
DataOutput/InputStream zu verwenden ist ok, ja, ein Reader ist noch ne Stufe höher wenn ich mich recht erinnere, mit Augenmerk auf Strings



> An InputStreamReader is a bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset. The charset that it uses may be specified by name or may be given explicitly, or the platform's default charset may be accepted.


----------



## Neuling... (14. Apr 2008)

Wieso vertraust du available / ready nicht ? Gibt es da einen Grund für ?


----------



## SlaterB (14. Apr 2008)

API InputStream zu available():



> Note that while some implementations of InputStream will return the total number of bytes in the stream, many will not. It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.
> 
> A subclass' implementation of this method may choose to throw an IOException if this input stream has been closed by invoking the close() method.
> 
> ...


----------



## Neuling... (14. Apr 2008)

Ok, aber JEDE Version liefert doch wenigstens 1 falls iwas zu lesen ist oder ? Sonst wäre doich diese Funktion ziemlich bescheuert und unbrauchbar.... Und wenn ja, wie kann man sowas denn überhaupt regeln ? Einen separeten Thread starten und nach einer gewissen zeit stream.close von außen aufrufen kann es ja wohl nicht sein, ich hoffe dass java da etwas eleganter vorgeht... ansonsten sind die streams doch für professionelle anwendungen unbrauchbar...


----------



## SlaterB (14. Apr 2008)

professionel gearbeitet habe ich damit noch nicht, deshalb will ich persönlich lieber nicht weiter spekulieren


----------



## Neuling... (14. Apr 2008)

Nein ist schon, ich will doch lediglich wissen als Anfänger, was man in so einem Fall lieber tun sollte, gibt es vernünftige Alternativen ? Ich mein wie wäre zum Beispiel folgendes Beispiel :


```
public class Learning
{
    public static void main(String[] argv) throws IOException
    {
    	if(argv.length < 2) return;
    	
    	ServerSocket SS = new ServerSocket(1234);
    	Socket Receiver = new Socket("localhost", 1234);
    	Socket Sender = SS.accept();
    	
    	byte[] array = new byte[4096];
    	
    	FileInputStream is = new FileInputStream(argv[0]);
    	BufferedInputStream bis = new BufferedInputStream(Receiver.getInputStream());
    	BufferedOutputStream bos = new BufferedOutputStream(
    			                   new FileOutputStream(argv[1]));
    	
    	int size, value;
    	
    	while((size = is.read(array)) != -1)
    	{
    		Sender.getOutputStream().write(array, 0, size);
    		Sender.getOutputStream().flush();
    		
	    	while((size = Receiver.getInputStream().available()) != 0)
	    	{
	    		value = bis.read();
	    		bos.write(value);
	    	}
    	}
    	bos.flush();	
    	
    	System.out.println("Programm geschlossen...");
    }
}
```

Es connected auf sich selbst, und schickt ne Datei in 4096 byte blöcken... so um nun nicht hängen zu bleiben, wird erst gefragt, ob man lesen kann, und wenn ja wird dass so oft gemacht, bis nichts mehr da ist, um nicht direkt auf die festplatte zu schreiben... nehme ich nicht nur den fileoutputstream...

SO wie die Beschreibung in der API dazu ist, könnte man denken, dass die Methoden available bzw. ready theoretisch nie 100 %  sagen können, ob auch nur ein Byte gelesen werden kann... So deshalb meine Frage:
Ist das so ok ?

ICH WILL NICHTS FALSCHES LERNEN 


Gruß


----------



## tuxedo (14. Apr 2008)

Naja, die API sagt ja nicht dass die Methode immer und völlig willkürlich Daten zurück liefert. Sie besagt nur, dass man sich nciht drauf verlassen soll, dass wenn "128" als Wert zurück kommt, dann auch wirklich exakt 128 Bytes da sind. Zwischenzeitlich könnten es schon mehr sein.

Ich hab die Erfahrung gemacht, dass der Wert in 99% der Fälle (meiner Fälle)  korrekt ist. Dennoch hab ich mich nicht drauf verlassen und hab mit dem Wert nicht versucht irgendwelche byte[]'s passend zu initialiiseren.

Ich hab damit nur überprüft ob überhaupt Daten (>=1) anliegen und dann in ein Array gelesen das ich vorher fest definiert hab (z.B. 512). Die read() Methode sagt dir dann genau wieviel gelesen wurde. 

- Alex


----------



## Neuling... (14. Apr 2008)

Gut, d.h. ich kann sicher sein, dass wenn available > 0 liefert, man definitiv ohne ein block read aufrufen kann richtig ?

Gurß


----------



## tuxedo (14. Apr 2008)

So seh ich das. Ja.

In der API ist das ja der ausschlaggebende Satz:



> It is never correct to use the return value of this method to allocate a buffer intended to hold all data in this stream.



D.h. du solltest sowas nicht machen:


```
byte[] b = new byte[in.available()];
```

Besser so:


```
byte[] b = new byte[128];
int bytesRead = in.read(b);
```

den "bytesRead" Wert solltest du auch im Auge behalten. Weil read() füllt nicht immer das ganze byte[]. 

- Alex


----------



## SlaterB (14. Apr 2008)

ärgerlich wirds, wenn man bei einem BufferedReader eine ganze Zeile lesen will oder bei einem ObjectInputStream ein Objekt,
aber nur der Hälfte der Bytes verfügbar ist


----------



## Neuling... (14. Apr 2008)

Und Variante 2 sollte man auch nur dann aufrufen, wenn available > 0 liefert richtig ?


----------



## tuxedo (14. Apr 2008)

@SlaterB

Deshlab verwende ich keine Buffered* ;-)

@Neuling...

Nein, nicht unbedingt. read() blockiert so oder so wenn keine Daten da sind und bricht ab, wenn der Stream geschlossen wird. In dem Fall ist dann bytesRead == -1

available() braucht man eigentlich nicht wirklich. 

Eine Sinnvolle verwendung für available hab ich noch nicht gefunden.


----------



## Neuling... (14. Apr 2008)

Nungut, aber wenn man nicht will, dass read blockiert! Dann macht es doch durchaus Sinn available zu verwenden, denn wenigstens ein byte zu lesen ist, dann wird read nicht blockieren und die tatsächlich gelesenen bytes als index zurück geben, so und auf avaiable ist doch zuminedst insofern verlass, dass es wenigstens unterscheiden kann, ob der nächste aufruf von read blockiert oder nicht oder ?


----------



## tuxedo (14. Apr 2008)

Wenn man nicht will das read() blockiert nimmt man Java NIO.
Ohne NIO blockiert read() IMMER solange bis was gelesen werden kann (und dann auch gelesen wurde) oder der Stream abbricht oder gewollt geschlossen wurde.

Und eben wegen diesem verhalten braucht man "available()" eigentlich nicht.

Alles andere ist Unsinn.


----------



## Neuling... (14. Apr 2008)

Oh mann, was teufel ist jetzt schon wieder NIO, nehmen denn diesen endlosen Klassen nie ein Ende -.-


----------



## tuxedo (14. Apr 2008)

NIO ist ein ganz anderes Konzept und nicht nur einfach eine andere Klasse. Das ist aber bei weitem komplizierter und im Netz mit weniger Tutorials dokumentiert als die Streaming-Sache. Ach ja: Bei NIO gibts keine Stream-Klassen mehr. 

Wenn du also unbedingt Streams haben und benutzen willst, dann musst du mit dem blockierenden read() Konzept auskommen.

NIO geht nunmal ganz andere Wege.

Verstehe auch nicht was so "problematisch" an dem blockierenden read() sein soll. Hab damit ohne größeren Probleme eine Audiokonferenz-Software mit Server+Client geschrieben. Und ich hab kein einziges mal available() benutzt.

- Alex


----------



## Neuling... (14. Apr 2008)

Ok, mal ne Erklärung in ein paar Sätzen bitte, was ist NIO ?
Du hast Recht, ich hab recht wenig gefunden im Internet, das Einzige was dabei rumkam, ist, dass ich jetzt weiß dass man für eine Socket Anwendung den SocketChannel benutzt...
Also ich meine gibt es denn gute Gründe um NIO zu benutzen ? wie du schon selber sagst, hast du diese Software auch damit geschrieben ... Also wozu wird dann diese NIO Konzept benötigt ? In meinem knapp 1000 Seiten umfassenden JavaBuch wurde kein Wort über dieses Thema verloren.. Kann es sein dass es rehct neu ist ?


----------



## tuxedo (14. Apr 2008)

Nein, NIO (New IO) ist seit Java 1.4 vorhanden (korrigiert mich bitte jemand wass ich dummes zeug erzähle?)..

NIO basiert auf Channels. NIO wird dann benutzt, wenn man entweder mit normaler Socketkommunikation nicht mehr weiter kommt (man bedenke: Jeder Client am Server wird in einem eigenen Thread behandelt!) oder man auf jedes klitzekleine bisschen Performance setzen muss.

Aber weil es nunmal so "komplex" ist und nicht mit je 10 Zeilen Code auf Server unc Clientseite auskommt und für viele Anwendungen "überdimensioniert ist, wird es wenig benutzt. 

Für die allermeisten Anwendungen ist das Stream-Konzept auch ausreichend. Auch RMI, was mit vielen JBoss und Co. Installationen zum Einsatz kommt, basiert auf dem Stream-Konzept. 

Mein Tipp: Bleib bei der Stream-Sache. Damit kommst du erstmal schneller ans Ziel. Und solange du nicht 1000 und mehr Clients vom Server bedient haben willst kommst du damit auch prima zurecht. 

Zu NIO nochmal in aller Kürze:

Mit NIO kann man die Datenverbindung mehrere Clients multiplexen um so nicht n Threads für n Clients benutzen zu müssen. Es reicht hier theoretisch 1 Thread für n Clients.

- Alex


P.S. Und nochmal: Es istz völlig okay und auch so gewollt read() blockieren zu lassen. Das tut keinem weh und braucht auch keine messbare CPU-Last....


----------



## Neuling... (14. Apr 2008)

Ahhhh, kann es sein, dass es ne Abwandlung von der C++/Socket -> select() Funktion ist ? Damit war dies auch in gewisser Weise möglich, ok vielen vielen Dank für die Infos!!

Gruß Chris


----------



## tuxedo (14. Apr 2008)

Jupp, das kommt in die Richtung.


----------



## Neuling... (15. Apr 2008)

Ok, aber ich starte noch einen aller letzen  Versuch xD, also du sagst für nicht-blockierendes IO verwendet man NIO, um zum beispiel nicht für Clienten einen neuen Thread zu starten, so aber (auch wenn es vlt unschön ist) ist das doch genauso mit den regulären Streams möglcih ?! Du hast gesagt, du hast noch keinen Grund gefunden, available sinnvoll einzusetzen, da read immer blockiert, aber das stimmt ja so garnicht, wenn available 0 liefert, ruft man einfach read für diesen Clienten nicht auf... und wenn er zum Bs. 30 sekunden lang, nicht available > 0 liefert wird die verbindung getrennt... kann sein, dass ich mich grad etwas vertuhe, aber WIESO sollte das so nicht gehen ? dann kann man auch alle Clienten in einem Thread behandeln, indem man dann in einer for-Schleife alle offnen Streams abklappert... und gegebenenfalls was macht... un wenn man erst 6 byte empfangen hat, aber man warten auf ein long ... dann kann auch in diesem Szenario erst nach 8 byte es als long interpretieren, ich sehe da jetzt ehrlich keinen Grund warum es damit nicht gehen sollte. Denn available sagt einem ja zumindest ob read blockieren oder nicht, und wenn man versucht 8 bytes zu empfangen mit read, aber man hat nur 6 bytes emfpangen wird ja read an der stelle nicht blockieren ! Oder doch ? Wenn ja dann versteh ich warum es mit den IOStreams nicht geht...

Gruß Chris


----------



## tuxedo (15. Apr 2008)

Prinzipiell würde das gehen. Ja. Aber das ist wohl alles andere als performant.

Bei NIO ist das ganze sozusagen eventbasiert. D.h. ich werde benachrichtigt wenn ein Client etwas übermitteln will.

Ständig "available()" abzufragen ist nicht das gelbe vom Ei und auch nicht im Sinne des Erfinders. Vor allem:

Was machst du in der Schleife in der du "available()" belästigst? Einfach immer und immer wieder available() fragen? Das kann auf die CPU gehen wenn sonst nix anderen in der Schleife zu tun ist... Oder du schläfst "künstlich" x Millisekunden. Aber das bremst das ganze ja unnötig aus.

read() blockieren zu lassen ist das effizienteste bei der Stream-Kommunikation. Alles andere ist gegen das Prinzip der streambasierten Technik in Java.

btw: Ich hab ja auch nicht gesagt dass es nicht möglich ist uneffizeint zu programmieren...


----------



## Neuling... (15. Apr 2008)

Alles klar du has mich überzeugt  xD Nagut danke für diese Diskusion !


----------

