# möglichst schnelle Datenübertragung?



## xumbu (19. Okt 2011)

Ich und ein Partner sind gerade dabei eine Software zu entwickelnd wobei es vor allem auf eine möglichst schnelle Datenübertragung ankommt.

Wir haben bisher immer ganze üblich Sockets.
Die Erfahrung die wir allerdings gemacht ist, dass uns die Übertragungsrate relativ langsam vorkam.


Meine Frage ist einfach, was momentan bei Java die beste Möglichkeit ist Daten zu übertragen.
Und ob es überhaupt etwas damit zu tun haben könnte.

Wenn ja. Wäre es hier vielleicht sogar sinnvoller auf eine andere Sprache auszuweichen.

Wie gesagt. Das wichtigste für uns ist momentan die Übertragungsgeschwindigkeit.


----------



## nillehammer (19. Okt 2011)

Plain Sockets und ein Protokoll mit möglichst wenig Overhead sind in Java IMHO schon das Schnellste, was geht. Auch wenn Java vielleicht etwas langsamer ist als native Sprachen, ist es in der Lage eine Netzwerkleitung auszulasten. Insofern würd ich alleine wegen des Speeds nicht die Sprache wechseln und die Ursache eher an anderen Stellen Eures Codes suchen.


----------



## xumbu (19. Okt 2011)

Ok gut, danke schon mal.

Aber was genau soll ich unter "möglichst wenig Overhead" verstehen.
Ich fange gerade erst an mich ernsthaft mit Netzwerkprogrammierung auseinander zusetzten. Sry dafür^^.



Wir auch darüber nachgedacht vielleicht sogar RMI zu benutzen. 
Hier auch wieder die Frage ob uns das ganze speedmäßig etwas einschränken würde oder ob dies auch fähig ist die Netzwerkleistung komplett auszulasten?

Wir wollen vor allem einfache ByteArrays hin und her schieben aber auch ganz simple Befehle(ein Integer + ein StringArray) an den Client senden.


----------



## Lumaraf (19. Okt 2011)

Für eine optimale Transferrate muß immer darauf achten die Daten nicht in zu kleinen Packete zu lesen und zu schreiben. Schau dir am besten mal BufferedInputStream und BufferedOutputstream an. In Java gibt es btw insgesamt 3 Möglichkeiten um mit Sockets zu arbeiten. (IO,NIO und AIO) Was davon am besten für einen ist hängt von diversen Faktoren ab.

Je nachdem wie wichtig die Transferrate ist und was für ein Budget zur Verfügung steht könnte man auch Infiniband-Karten kaufen und die Datenübertragung darüber laufen lassen. Damit sind in der Theorie auch Transferraten von mehreren Gigabyte pro Sekunde möglich.


----------



## nillehammer (20. Okt 2011)

> Aber was genau soll ich unter "möglichst wenig Overhead" verstehen.


Overhead ist der Anteil der Daten, der keine Nutzdaten enthält, sondern nur Protokollinformationen (Header etc.). Http+XML (z.B. Webservices) hat vergleichsweise viel Overhead, RMI sicher weniger, Werte direkt in Streams schreiben sicher am wenigsten.


----------



## Xumbu (20. Okt 2011)

was uns z.B aufgefallen ist, war z.B, dass die übertragung von wenigen mb schon über lan länger dauerte als erwartet.

wir haben das ganze als byteArray über einen *ObjectOutputStream* gesendet.
Könnte es etwas damit zu tun haben?


----------



## Tomate_Salat (20. Okt 2011)

Wenn du die übertragung so klein wie möglich halten willst, würde ich nicht den ObjectOutputStream verwenden. Mal ein Beispiel von einem Protokoll von mir: JOSParser[1], sehr einfach gehalten und unterstützt noch nicht alles, wie gewollt, aber die Größen Sprechen für sich: :


> ```
> Protokoll: [{12|7}Tomate_Salat[{2}19]]
> JOS: 27 bytes    <-- JOS verbraucht 27 bytes
> OoS: 128 bytes   <-- ObjectOutputStream locker 100bytes mehr.
> ...



Vllt schaut ihr euch mal google-gson - A Java library to convert JSON to Java objects and vice-versa - Google Project Hosting an und vergleicht dort die Größen der Serialisierung.




[1] und werde ich höchstwahrscheinlich nicht mehr weiterentwickeln


----------



## Kr0e (20. Okt 2011)

ObjectOutputStream ist nicht die beste Wahl, jedoch sollten die byte[]-Arrays 1:1 als raw Daten durchgehen mit minimal Overhead.

Meine Empfehlung für maximalen Datentransfer ist meiner Ansicht nach AIO - Asynchronous IO (Seit JDK7)

NIO ist der JDK1.4 Ansatz für non-blocking IO mit einer überschaubaren Menge an Threads. Aber AIO nutzt je nach Plattform die ideale Impl. (zwar ähnlich wie NIO, aber wohl performanter und vorallem einfacher zu benutzen!). Wenn das ganze nun kombinierst und ich rede nicht nur von der Übertragung sondern auch vom Lesen/SChreiben der Daten in/aus eine Datei... Alles mit AIO und du hast quasi keine unnötigen Wartezeiten drin und lässt alles das OS machen.

Außerdem sollten die byte[]-groß genug gewählt sein, sonst gibt es Latenz-Overhead, da sonstn TCP andauernd die Frames kontrollieren muss wodurch Contextwechsel überwiegen. Sprich TCP kommuniziert ja andauernd mit der Gegenseite um zu überprüfen, ob Daten gesendet werden können z.b. (Ist der Socketbuffer voll und wurde nicht genutzt bisher, wird uach nichts mehr empfangen...)

Zwischen simplen TCP und hardcore TCP-Tunig liegen Welten:

TCP tuning - Wikipedia, the free encyclopedia

DAs alles wird aber erst bei Gigabitnetzwerken richtig interessant... Im Lan mit einer maximalen Rate von 12,5 MB/s (theoretischer WErt) erreicht man das Maximum locker auch mit simplen Streams und ohne iwelche TRicks


----------



## homer65 (20. Okt 2011)

Es kann durchaus Sinn machen die Daten vorher zu komprimieren.
Ist halt die Frage ob sich eure Daten gut komprimieren lassen.


----------



## xumbu (20. Okt 2011)

Tomate_Salat hat gesagt.:


> Wenn du die Übertragung so klein wie möglich halten willst, würde ich nicht den ObjectOutputStream verwenden.




So machen wir es im Moment: 


upload:

```
ObjectOutputStream objOut = new   ObjectOutputStream(client.getOutputStream());                
objOut.writeObject(obj);
objOut.flush();
```

download: 

```
ObjectInputStream objIn = new ObjectInputStream(client.getInputStream());    
obj = objIn.readObject();
```
(in der Variable 'obj' steht in der Regel ein byteArray. Kann aber auch ein Befehl sein, wie gestern schon angesprochen.)


Angenommen in obj steht nichts anderes als ein byteArray mit bspw. der Größe 50mb.
Wie große wäre jetzt das Objekt, welches versendet wird? Macht es bei solchen Größen überhaupt einen Unterschied oder handelt es sich hierbei nur um wenige Bytes? 
Wieso wäre das also die schlechtere Variante?


----------



## Tomate_Salat (20. Okt 2011)

Ob die Standardserialisierung mit byte-arrays oder Strings anderes umgeht als mit normalen Objekten weiß ich so nicht. Müsste man ausprobieren. Aber Objekte werden dort nunmal komplett serialisiert (auch informationen die du eigentl. nicht brauchst). 

Hast du ein Testobjekt von 50Mb? Dann probiers doch einfach mal aus: Sende die Daten einmal mittels Object*Stream und sende Sie einmal direkt mit [japi]OutputStream#write(byte[])[/japi]. Dann kannst du vergleichen.

Wenn du die anzahl an versendeten bytes sehen willst, dann nimm einfach ein [japi]ByteArrayOutputStream[/japi], schreib die Daten darein. Danach lässt du dir das byteArray zurückgeben und prüfst die länge.


----------



## Kr0e (20. Okt 2011)

Das Ergebnis kann ich dir jetzt schon sagen, ich habe mich relativ intensiv mit dem Object*Stream beschätigt, um aus den Fehlern zu lernen. OOS benutzt 2 Arten von Daten: Einmal die Blockdaten und einmal Objektdaten. Primitive typen und primitive Arrays sind Blockdaten. Das benötigt laut Impl. alle 1024 Bytes 5 Bytes Overhead (Ist der Impl zu entnehmen). Sprich byte[] werden relativ unbehandelt mit minimalem Overhead durchgereicht, das ist alles schon recht clever gemacht, allerdings noch lange nicht perfekt, voralllem, weil ich Blockdaten für sinnfrei halte. Die könnten einfach Streamdaten mit einem Längenindex am Anfang verschicken, aber die verschicken alle 1024 bytes Längen Indeces, was schwachsinnig ist, aber die ganze Impl vom OSS wirkt arg zusammen gewürfelt.

AUßERDEM darf man eines nicht vergessen, ByteBuffer sind um einiges schneller, vorallem dank JDK 7 (Mist, wo war doch glecih der Artikel dazu!). Man soll seit JDK7 direkt Puffer den Heapbuffern bevorzugen. Die sind nun schneller, als in VM Kopieraktionen. Sprich Streams sind generell eigentlich nicht wirklich geeignet, wenn es wirklich auf Geschwindigkeit ankommt..


----------

