# Schnellster Stream



## Stiewen (13. Aug 2008)

Hi Guys,
ich moechte mal die Frage ins Forum stellen, welcher Stream am schnellsten ist und warum - bzw. welcher ihr glaubt am schnellsten zu sein und warum?

Bisher verwende ich den ObjectStream mit folgendem Code:


```
// oisFromClient IST EIN OBJECTOUTPUTSTREAM, SCHON VERBUNDEN

FileOutputStream fosFile = new FileOutputStream ( new File ( ">DATEINAME<" ) );
        	
        	int intLen = 6020;
        	byte[] byBytes = new byte [ intLen ];
            while ( ( intLen = oisFromClient.read ( byBytes ) ) > 0 ) {
            	fosFile.write ( byBytes, 0, intLen );
            	fosFile.flush (  );
            	
            }
            
            fosFile.close (  );
```

Ich hatte mir erhofft durch den groesseren Byte-Array, schneller die Daten senden zu koennen. Weiss aber nicht so recht, ob das erfolgreich waere. Koennt ihr was dazu sagen?


LG Stiewen


----------



## Beni (13. Aug 2008)

Oft bringt ein BufferedOutputStream nochmal ein gutes Stück Performance.

Du könntest auch mal die "NIO" (new IO), eigentlich das Package "java.nio", anschauen. Damit soll man auch ziemlich Geschwindigkeit gewinnen (ich habe selten damit gearbeitet, aber im Netz gibt es sicherlich Tutorials dazu).

Und dann fragt es sich noch, ob du unbedingt einen ObjectStream verwenden musst, Serialisierung ist nicht gerade die schnellste Operation. Wenn es einfache Daten sind, könntest du die vielleicht auch direkt z.B. in einen DataOutputStream schreiben.


----------



## Stiewen (13. Aug 2008)

Prob ist, dass ich strings damit sende und gleichzeitig mit dem Code oben noch files. Die strings sende ich einfach mit sendObject (String).

Aber NIO werde ich mir dann wohl mal ansehen muessen. Danke


----------



## tuxedo (13. Aug 2008)

Kann dir gleich sagen: NIO ist nicht einfach... gar nicht einfach. Tutorials gibts einige, aber das alleine reicht nicht wirklich aus. Viele verallgemeinern gewisse Beispielcodeabschnitte, so dass einem wichtige Teile immernoch fehlen. 

Kann dir aber das Buch "Java NIO" empfehlen. 

Nebenbei: Was macht du denn da eigentlich? Was ist mit RMI oder SIMON? Machen die nicht schon das was du brauchst/willst? Objekte schicken und so ...

 - Alex


----------



## Stiewen (14. Aug 2008)

ich will ein prog schreiben, dass dateien von a nach b sendet. Skype ICQ und Co sind mir da zu langsam. Nun wollte ich versuchen, ob es schneller geht, wenn man selbst was schreibt.

Bisher habe ich eine maximale rate von vll 40 kbits. Auch mit dem BufferedOutputStream, der oben erwaehnt wurde. Den habe ich eingebaut:


```
try {
			soClient = ssServer.accept (  );
			oosToClient = new ObjectOutputStream( new BufferedOutputStream ( soClient.getOutputStream (  ) ) );
			oisFromClient = new ObjectInputStream( new BufferedInputStream ( soClient.getInputStream (  ) ) ); 			
			
		} catch ( IOException ioe ) {}
```

Mache ich was falsch oder warum bekomme ich bei DSL 2000 die bits nichts mit 200kbits rueber oder schneller rueber? Auch die andere seite hat DSL 6000 und mein progi macht mit dem source da oben nur 40kbits oder weniger ... 

- Stiewen


----------



## Murray (14. Aug 2008)

Wenn Du nicht wirklich Java-Objekte von einer VM zur anderen transportieren willst, dann verwende keine Object(In/Out)putStreams - die sorgen für einen zusätzlichen Overhead. Um eine Datei von A nach b zu schicken, musst Du die Datei auf der einen Seite byteweise lesen, die Bytes dann ebenfalls byteweise zur anderen VM schicken und dort alles wieder byteweise in eine Datei schreiben.


----------



## Stiewen (14. Aug 2008)

und was mache ich mit den strings? dann muss ich die ja auch byteweise schicken. und letztendlich auch ein STOPP-Zeichen machen. ... find ich persoenlich nicht so gut. oder kennt ihr da noch ne andere loesung, wenn der stream immer offen bleiben soll und mal strings und mal files senden soll?


----------



## Murray (14. Aug 2008)

Richtig, Du musst Dich in diesem Fall selbst darum kümmern, dass alle Nutzdaten in eine sinnvolle Byte-Repräsentation umgewandelt und auf der anderen Seite als äquivalente Objekte wiederhergestellt werden. Und auch ein rudimentäres Übertragungsprotokoll (einfache Stoppzeichen werden nicht reichen, denn alle 256 möglichen Bytewerte können in den Nutzdaten ja vorkommen) brauchst Du. 
Aber eins geht nur - den "Komfort", den man durch Nutzung mit der fertigen Objektserialisierung bekommt, erkauft man durch einen gewissen Laufzeitoverhead.


----------



## Stiewen (14. Aug 2008)

Was koennte man also fuer ein Stoppzeichen nehmen? Ich denke da an ASCII-Werte kleiner als 32, weil darueber ja alles gesendet werden kann. unter 32 (was das leerzeichen ist) werden ja fuer die steuerung benutzt am rechner oder sonst was, weiss ich nicht. demnach denke ich,dass man (ASCII-Wert) 1 nehmen, oder?


----------



## Murray (14. Aug 2008)

Wie gesagt - wenn Du beliebige Dateien (nicht nur Textdateien) schicken willst, dann kann da alles drin vorkommen, und Du kannst kein Stoppzeichen definieren. Aber Du könntest z.B. bei einer Datei zuerst die Länge übertragen; dann weiß die Gegenseite, wieviel Zeichen sie lesen muss.


----------



## Stiewen (14. Aug 2008)

Super, das werde ich so machen mit der Laenge der zu sendenen Daten. Danke!

Jetzt wuerde ich nur noch die Fragen stellen, 

1. wie soll ich die laenge senden und welchen stream sollte ich denn nun nehmen, damit es am schnellsten geht? ich nehme jetzt einfach mal den dataoutputstream und sende ein Double wert, der die laenge beinhaltet in MB.
Oder waere doch ein ObjectOutputStream am besten, der vom Socket den output holt, damit ich dann nur die bytes sende. doch dann stelle ich mir die frage, wie man dann eine zahl senden kann!!!

2. ob es besser ist einen grossen (zB. new Byte [6020]) oder eher einen kleinen (new Byte [1024]) byte zum senden zu nehmen? oder vll doch noch weniger bzw. mehr? was waere optimal und warum?


----------



## Gast v2.0 (14. Aug 2008)

für was braucht man die stopp-zeichen, wenn ich fragen darf?


----------



## Stiewen (14. Aug 2008)

damit du siehst, wann deine nachricht beziehungsweise die datei, die du sendest, vorbei ist. ansonsten versucht er immer weiter zu lesen.

ABER: die idee mit der laenge ist viel besser, weil du dir kein zeichen einfallen lassen brauchst, weil sowieso fast alle zeichen nicht gut waeren, weil sie in einer datei vorkommen koennten oder in einem string.


----------



## Murray (14. Aug 2008)

Wenn es möglichst effizient sein soll: nimm einen (Buffered)OutputStream und schreibe nur Bytes. Wenn Du die Länge (da reicht wohl ein int) schreiben willst, dann zerlege den Integer-Wert in seine vier Bytes und schreibe die nacheinander. Und auf der anderen Seite machst Du aus den ersten vier gelesenen Bytes wieder einen int-Wert. Das ist alles natürlich sehr "low-level", aber das ist der Preis dafür, den gesamten Vorgang unter Kontrolle zu haben und so den Overhead zu minimieren.

Was das Byte-Array für den Read-Buffer angeht: zumindest dann, wenn Du einen BufferedInputStream zum Lesen verwendest, ist das vermutlich fast irrelevant; zu klein sollte der Buffer nicht sein, denn über das Netz gehen die Daten ohnehin paketweise - ich würde es mal mit einen KByte versuchen. Du kannst den Wert dann später hochsetzen und ausprobieren, ob das überhaupt messbare Effekte hat.


----------



## Guest (14. Aug 2008)

du könntest doch auch einfach zwei sockets verwenden, einen für daten, den anderen
für text-nachrichten.

...wenn eine datei fertig übertragen ist bekommt man doch "-1" übergeben und weiss bescheid?! deswegen wundert mich das mit den stopp-zeichen.

tschuldigung fals ich doofes zeug rede ^^


----------



## Stiewen (14. Aug 2008)

A) das ist alles richtig, doch dann brauchst du auch 2 ports. und genau das will ich vermeiden.

B) will ich einen ganz simplen und universalen server/ client schreiben, der in meinen spaeteren programmen auch noch zum einsatz kommen kann.

C) Zu der integer laenge moechte ich aber sagen, dass die daten ziemlich gross sein koennen. darum wuerde ich schon eher long nehmen. weiss nicht, was int maximal darstellt, doch es ist mir auch egal. Denn je groesser ich das JETZT einstelle, desto laenger kann ich das prog nutzen, wenn daten in groessenverhaeltnissen von TB normal sind  (ich weiss, dass man dann auch andere streams und so hat ^^ )


----------



## Murray (14. Aug 2008)

Stiewen hat gesagt.:
			
		

> C) Zu der integer laenge moechte ich aber sagen, dass die daten ziemlich gross sein koennen. darum wuerde ich schon eher long nehmen. weiss nicht, was int maximal darstellt, doch es ist mir auch egal. Denn je groesser ich das JETZT einstelle, desto laenger kann ich das prog nutzen, wenn daten in groessenverhaeltnissen von TB normal sind  (ich weiss, dass man dann auch andere streams und so hat ^^ )



Die 32 Bit von Integer reichen tatsächlich nicht unbedingt für alle möglichen Dateien aus (ISO-Images von CDs passen noch; bei DVDs wird es eng) - insofern solltest Du wirklich auf Long setzen; damit bist Du auch in guter Gesellschaft: java.io.File.getLength ist auch als Long definiert.


----------



## Stiewen (14. Aug 2008)

Danke fuer diese hilfreichen Beitraege!


*- ready to close the topic*


----------



## tuxedo (15. Aug 2008)

Kleine anmerlung am Rande:

>> Mache ich was falsch oder warum bekomme ich bei DSL 2000 die bits nichts mit 200kbits rueber oder schneller rueber? Auch die andere seite hat DSL 6000 und mein progi macht mit dem source da oben nur 40kbits oder weniger ... 

Bist du dir sicher dass du nicht kbits mit kbytes verwechselst?
Mit was  hast du den Transfer gemessen?

Hinzu kommt übrigens: Mit den Streams verwendest du automatisch TCP. Und da gibt's den "Nagle Algorithmus" der von Haus aus eingeschaltet ist. Schaltet man diesen aus, so läuft die Sache schneller. Allerdings sollte man dann auf Nummer sicher gehen dass auch tatsächlich alles ankommt.

- Alex


----------



## Murray (15. Aug 2008)

alex0801 hat gesagt.:
			
		

> Mit den Streams verwendest du automatisch TCP. Und da gibt's den "Nagle Algorithmus" der von Haus aus eingeschaltet ist. Schaltet man diesen aus, so läuft die Sache schneller.



Ist es nicht eigentlich so, dass der Nagle-Algorithmus lediglich das Versenden zu kleiner Pakete unterbindet und dadurch den Durchsatz sogar verbessert? Die Reaktionszeit wird dadurch zwar verlängert; wenn man aber wirklich große Datenmengen hintereinander verschicken will, dürfte die Übertragungsrate aber eher besser sein als mit TCP_NODELAY, weil die Kapazität besser ausgenutzt wird.


----------



## tuxedo (15. Aug 2008)

Stimmt, ich erinner mich. Da war was mit der Paketgröße.... (http://de.wikipedia.org/wiki/Nagle-Algorithmus).

Die verwechslung kbyte / kbit könnte dennoch sein.

Bei meinem DSL6000 (6000kbit down/521kbit up) krieg ich Peaks von bis zu 77kbyte/sek hin.

Wirklich große Datenmengen (ganze CDs) dauern auch da wenn man sie uploaded. Und noch schlimmer ist es, wenn man von DSL2000 (normalerweise 2000kbit down/192kbit up) zu DSL6000 was hochladen will...

Bei DSL2000 sollten in etwa 30kbyte/sek als maximum drin sein (wenn ich mich  nicht verrechnet habe).

- Alex


----------

