Input/Output Dateien >65536B über Sockets übertragen

Blackhole16

Bekanntes Mitglied
Ich habe ein Programm geschrieben, mit dem ich 2 Ordner auf 2 verschiedenen PCs abgleiche und auf beiden PCs dann immer die neuesten Dateien habe. Bisher habe ich immer jedes Byte einzelon gelesen, gesendet und geschrieben, was auch perfekt funktioniert hat. Aber das ist mir doch ein wenig zu langsam ;)
Also wollte ich die Datei komplett in einen byte[] buffer schreiben, um diesen dann komplett senden zu können und wieder zu schreiben, was die Geschwindigkeit wohl sehr erhöht.
Gleich bei dem ersten Versuch ist mir aufgefallen, dass der gesendete Buffer nicht größer als 65536 sein kann, da nur so viel auf einmal gesendet bzw. empfangen wird (in.read() war immer maximal 65536). Also habe ich jetzt versucht den Buffer in solche kleine Stückchen zu zerteilen und diese dann zu senden.
Dies habe ich so realisiert:
Senden:
Java:
byte[] buffer = new byte[(int)files[i].length()];
filein.read(buffer);
while (buffer.length != 0) {
	if (65536 >= buffer.length) {
		os.write(buffer);
		buffer = Arrays.copyOfRange(buffer, 0, 0);
	} else {
		buffer = Arrays.copyOfRange(buffer, 65535, buffer.length);
		os.write(buffer);
	}
	System.out.println(buffer.length);
}

Empfangen:
Java:
byte[] buffer = new byte[65536];
int len = 0;
while (len < length) {
	int len1 = is.read(buffer);
	System.out.println(len1);
	len+=len1;
	System.out.println(len + "  " + length);
	fileout.write(buffer);
	buffer = new byte[65536];
}

filein und fileout sind die FileInput/OutputStreams zur lokalen Datei. os und is sind die Input/OutputStreams über den Socket. length ist die Länge der Datei, die vorher über einen String an den Empfänger gesendet wird.

Bis zu dem Zeitpunkt des Sendens sind alle gesendeten und empfangenen Dateien vollkommen richtig. Aber bei Dateien größer als 65536 Bytes funktioniert mein Programm nicht richtig.
Hier einmal die Ausgabe beider programme:

Code:
Empfänger:
Alt+Ziffern.odt;1341776898972;20602
Recieving D:\TEST_recieve\Alt+Ziffern.odt
20602
20602  20602
File written
Angebot44441 (1).pdf;1341776899721;140298
Recieving D:\TEST_recieve\Angebot44441 (1).pdf
65536
65536  140298
18455
83991  140298
9260
93251  140298

Sender:
Code:
Alt+Ziffern.odt;1341776898972;20602

Sending D:\Daten\Alt+Ziffern.odt
0
Angebot44441 (1).pdf;1341776899721;140298

Sending D:\Daten\Angebot44441 (1).pdf
74763
9228
0
Busplan.ods;1341776900018;14465

Erst wird der übertragende String ausgegeben:
Dateiname.endung;lastModified();length()
Nur zur Kontrolle habe ich diese hier mal ausgeben lassen.

Alt+Ziffern.odt ist 20,1kb groß, wird aber geschrieben als 64KB groß. Ich denke, dass das an dem Buffer liegt, der zum Schluss eh nur lehr ist. Das kann ich aber (hoffe ich mal) auch alleine lösen.
Angebot... ist 137KB groß und bei dieser Datei gibt, wie man sieht, Fehler.

Wie man an dem Konsolenoutput gut sehen kann, wird weniger gelesen als geschrieben über den Socket.

Woran liegt das?

mfg
BH16

PS: Ich weiß, dass es viele Beispiele dafür gibt und ich diese einfach copy/pasten könnte, aber mir ist der Lerneffekt lieber, weswegen ich jetzt hier frage. Ich bin desweiteren schon seit mehr als 7 Stunden dabei NUR dieses eine Problem zu lösen und habe es auch schon über einen DataI/OS probiert, wobei da genau das selebe Problem mit den 65536 Bytes war.
 

homer65

Top Contributor
Anstatt bytes einzeln oder als Buffer zu übertragen kann man auch direkt Java Objekte mittels ObjectOutputstream bzw ObjectInputStream übertragen.
Das hatt sicherlich etwas Overhead wegen der Serialisierung der Daten.
Ist nur die Frage ob die Performance für dich trotzdem ok ist. Einfach mal ausprobieren.
Es vereinfacht aber das Verfahren für den Programmierer erheblich.
Man muss sich um solche Sachen wie 64K Grenzen keine Gedanken machen.
Wenn es dich interessiert, kann ich ein Code Beispiel posten.

Edit: Tippfehler korregiert
 
S

SlaterB

Gast
Windows ist zunächst nicht an den Fehlern im Großen schuld, der Sende-Code ist völlig abgedreht

der Sender könnte einfach sein 140.298er Array senden und fertig, wo genau ist dabei ein Problem?
dass der Empfänger vielleicht nur maximal 65.536 auf einmal liest, kann man dort ja in einer Schleife lösen,
ein Problem muss das auch nicht sein, sind einfach die ersten bytes die mit dem oder den ersten Paketen übertragen wurden,


was passier aber aktuell mit den 140.298 Bytes beim Sender?
Java:
byte[] buffer = new byte[(int)files[i].length()];
filein.read(buffer);
while (buffer.length != 0) {
	if (65536 >= buffer.length) {
		os.write(buffer);
		buffer = Arrays.copyOfRange(buffer, 0, 0);
	} else {
		buffer = Arrays.copyOfRange(buffer, 65535, buffer.length);
		os.write(buffer);
	}
	System.out.println(buffer.length);
}
im 1. Durchlauf wird der else-Fall aktiv, es wird ERST der buffer verkleinert, 65.535 Bytes gehen schonmal verloren,
übrig bleiben 74.762 Bytes, diese werden auch gleich komplett gesendet,
nicht nur ein bisschen, der ganze Buffer, von dem erstmal reichlich weggeschmissen wurde, geht ins write()

2. Durchlauf:
wieder else, wieder Wegschmeißen, es bleiben 9226, die werden dann auch gesendet, zum zweiten Mal,
denn der erste Durchlauf hatte schon alles gesendet (nachdem einiges komplett verloren ging)

3. Durchlauf:
nun darf das if dran, die verbleibenden 9226 Bytes werden zum 3. Mal (!) gesendet

Summe: 74.762 + 9226 + 9226 = 93.214


hmm, sind nicht genau 93.251, da sehe noch keine Erklärung,

falls das so korrekt notiert ist und nicht noch anderes gesendet wird,
dann könnte man das genauer untersuchen:
1. alle Parameter verkleinern, in 100er oder 10er-Portionen senden, solange dort auch Fehler auftreten,
2. kleinere Beispiele, etwa welche die nur knapp über 65.536 bzw. der neueren kleineren Test-Grenze liegen
3. kontrolliere bytes senden, z.B. Folgen 0, 1, 2, 3 .. usw. wiederholend,
genau anschauen welche Bytes ankommen, in welcher Reihenfolge, wo ist die Reihe ungewöhnlich, z.B. 0-Werte
4. im Extremfall einzelne Bytes des Senders, z.B. kurz vor Ende, auf Werte setzen die sonst gar nicht vorkommen,
wie wirkt sich das auf die unerklärlichen Bytes aus usw., werden die letzten x verdoppelt oder was passiert genau
 
Zuletzt bearbeitet von einem Moderator:

Blackhole16

Bekanntes Mitglied
Danke für die beiden Antworten.

@Spacerat: Irgendwie versteehe ich den ganzen Windoof Kram, der da steht nicht so ganz. Was muss ich also genau machen, damit es geht?

@homer: Solange es schneller ist, als die Bytes einzeln (wie ich es zuerst gemacht habe ;) )zu übertragen, nehme ich es gerne an ;) Ja, kannst du bitte ein Beispiel posten, da ich mit OOS noch nichts zu tun hatte, habe es auch gerade ganz billig mit new OOS(os).write(buffer) und int len = new OIS(is).read(buffer) gemacht, len war da aber sogar nur 1024 groß o_O

@slater: habe schon geschrieben, als deins veröffentlicht wurde, ich schaue es mir gerade an und antworte danach. OMG du hast ja recht, das ist so ein müll. Da sieht man, dass ich Anfänger in sachen sockets bin-.-

mfg
BH16
 
Zuletzt bearbeitet:

Blackhole16

Bekanntes Mitglied
Ich habe jetzt, nachdem mir slaterb meinen Müll erklärt hat den Algo nochmal verändert. Jetzt funktioniert es einwandfrei, selbst mit großen Daten und ich bin auch mit der geschwindigkeit sehr zufrieden (bisher nur LH, gleich kommt aber auch der "echte" test).
Hier nun mein Code zum senden (ja, sher einfahc ;) )

Java:
byte[] buffer = new byte[(int)files[i].length()];
filein.read(buffer);
os.write(buffer);

und hier zum lesen:

Java:
byte[] buffer = new byte[(int)length];
int lenRead = 0;
int lenLeft = (int)length;
while (lenRead < length) {
	int lenTemp;
	if (lenLeft > 65536)
		lenTemp = is.read(buffer, lenRead, 65536);
	else
		lenTemp = is.read(buffer, lenRead, lenLeft);
	System.out.println(lenTemp);
	lenRead+=lenTemp;
	lenLeft-=lenTemp;
	System.out.println(lenLeft + "  " + lenRead);
	fileout.write(buffer);
}

Damit funktioniert es perfekt. Danke euch allen.

@homer+spacerat: Wenn ihr möchtet, könnt ihr es noch erklären/posten, ihr müsst es aber nicht, da ich jetzt ja alles gelöst habe ;)
 
S

SlaterB

Gast
auf Sender-Seite wäre es human, auch nur mit einem Buffer aus der Datei zu lesen und weiterzureichen,
damit immer nur ~65536 Bytes im Speicher sind, nicht zig MB, irgendwann gibts auch Grenzen

das Empfangen ist auch unnötig kompliziert und wieder mit großem Array,
es könnte quasi derselbe universale Code zum Übertragen von einem Stream in den anderen genutzt werden

kopiert von
Datei mittels TCP übertragen @ tutorials.de: Tutorials, Forum & Hilfe

Datei senden:
Java:
OutputStream out = socket.getOutputStream();
InputStream fileIn = new FileInputStream(file);
 
byte[] buffer = new byte[1024];
while (fileIn.available() > 0) {
    out.write(buffer, 0, fileIn.read(buffer));
}
 
fileIn.close();

Datei empfangen:
Java:
InputStream in = socket.getInputStream();
FileOutputStream fileOut = new FileOutputStream("dateiname.ext");
            
byte[] buffer = new byte[1024];
while (socket.isConnected()) {
    int bytesRead = in.read(buffer);
    if (bytesRead == -1) break;
    fileOut.write(buffer, 0, bytesRead);
}
ok, gleich ist der nicht ganz auf beiden Seiten,
aber jedenfalls kürzer (am Empänger bisher) und speicherschonender
 

Blackhole16

Bekanntes Mitglied
Danke, ich werde es bei Gelegenheit (in 1-2 Tagen) ausprobieren, da in wenigen Momenten ein Freund kommt, mit dem erst einmal gesuchtet wird ;D. Komisch ist nur, dass ich auf der Empfängerseite 110MB RAm brauche und auf Senderseite nur 30MB. Kann das vllt daran liegen, dass ich beim sender 32bit und beim Empfänger 64bit habe?

Und wäre das denn schneller als mein jetziger code (von der Übertragung her)? Jetzt übertrage ich ein 5MB Bild in ca 2 secs, was, finde ich, doch schon ziemlich schnell ist ;)

mfg
BH16
 
S

SlaterB

Gast
schwer zu sagen, zusätzliche Arbeit an mehr Methodenaufrufen steht Speicherallokierung für Mega-Array gegenüber,
ich vermute spontan dass deins minimal schneller ist, nur ab Größe x gibts den GAU,
und andere Programmteile, die auch bisschen Speicher haben wollen werden unterhalb der GAU-Grenze geärgert,
unschön
 
S

Spacerat

Gast
Das ist kein Windowsfehler, sondern Einstellungssache. Was da genau passiert weis ich auch nicht, nur das der Empfänger dadurch manchmal nicht mehr als ein Paket (64KB) bekommt und der Rest auf der Strecke bleibt. Hat was mit Blocking- bzw. NonBlocking-Buffers zu tun und dem Umstand, dass eine Empfangsbestätigung gesendet, aber der Puffer nicht geleert wird. Wenn der Empfangsbuffer nach 64KB blockt und der Sendepuffer ein nicht blockierender ist, schreibt der Sendepuffer alles was über die Puffergrösse hinaus geht in den Hades. Deshalb wird auf der MS-Seite unter anderem auch die Verwendung von blockierenden Puffern vorgeschlagen.
Wie SlaterB schon sagt, verwendet man auf beiden Seiten einer Socketverbindung nur einen einzigen Stream. Eigentlich gibt es pro Seite und Richtung auf jeder Seite ja auch nur einen.
Diese Streams lassen sich in Java beliebig Schachteln und nicht nur mit ObjectStreams. Ich schalte z.B. auf beiden Seiten gerne mal 'ne Pipe mit Puffern <= 16KB dazwischen, damit die Socket-Buffer nicht blockieren. Soweit ich weis, verwendet die Java-IO-API ohnehin nur Puffergrössen bis 8KB.
 
Zuletzt bearbeitet von einem Moderator:

AquaBall

Top Contributor
Ohne die obigen Antworten zu ignorieren, deine read-Methode ist schon umständlich formuliert.
Java:
byte[] buffer = new byte[(int)length];
int lenRead = 0;
int lenLeft = (int)length;
while (lenRead < length) {
    int lenTemp;
    if (lenLeft > 65536)
        lenTemp = is.read(buffer, lenRead, 65536);
    else
        lenTemp = is.read(buffer, lenRead, lenLeft);
    System.out.println(lenTemp);
    lenRead+=lenTemp;
    lenLeft-=lenTemp;
    System.out.println(lenLeft + "  " + lenRead);
    fileout.write(buffer);
}

Mit weniger Variablen und dem 'natürlichen' Ablauf folgend wird's IMHO leichter verständlich:
Java:
byte[] buffer = new byte[(int)length];
int blockSize=0x10000;  //=dezimal 65536
int lenRead = 0;
while (lenRead < length) {
    blockSize = Math.min(length-lenRead,blockSize);  // Entweder in Blockgröße, oder Restlänge
    is.read(buffer, lenRead, blockSize);  // lesen
    fileout.write(buffer);  // schreiben
    lenRead+=blockSize;  // Position merken
}
 
S

SlaterB

Gast
> fileout.write(buffer);
in der Schleife kann in beiden Varianten nicht gehen, wie ich jetzt sehe,
erst nach der Schleife, wenn der buffer erst gefüllt ist..
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I Dateien aus dem Resource Folder laden Java Basics - Anfänger-Themen 2
A Thread XML-Dateien zusammenfügen Java Basics - Anfänger-Themen 11
Buroto Threads Verschiedene .txt Dateien Auf Listen und Verbinden Java Basics - Anfänger-Themen 3
J Dateien lesen und schreiben Java Basics - Anfänger-Themen 5
B Jar Dateien ohne IDE verwenden? Java Basics - Anfänger-Themen 1
A Optimierung eines Programms: Mergen der Dateien Java Basics - Anfänger-Themen 23
A Zwei XML-Dateien Mergen Java Basics - Anfänger-Themen 14
A Input/Output Mehrere Csv-Dateien einlesen Java Basics - Anfänger-Themen 2
LetsSebi Dateien werden nicht in Zip gespeichert Java Basics - Anfänger-Themen 1
J Alle .java Dateien von einem Verzeichnis in eine Zip speichern Java Basics - Anfänger-Themen 2
J Alle Dateien aus einem Verzeichnis laden Java Basics - Anfänger-Themen 10
MiMa log4j als separate Dateien in Schleife? Java Basics - Anfänger-Themen 6
M Scannen von *.txt - Dateien; wo sind der oder die Fehler? Java Basics - Anfänger-Themen 4
A Input/Output Dateien einlesen und ausgeben Java Basics - Anfänger-Themen 7
S Lese- / Schreibfähigkeit von Dateien sicherstellen Java Basics - Anfänger-Themen 1
C "HelloWorld" - Dateien erstellt, aber ist es eine class-Datei? Java Basics - Anfänger-Themen 2
J Java findet plötzlich die Dateien im Projekt nicht mehr. Java Basics - Anfänger-Themen 12
J Dateien in Verzeichnissen rekursiv auflisten wirft Exception Java Basics - Anfänger-Themen 4
L Classpath Alle Dateien im Classpath finden Java Basics - Anfänger-Themen 4
MiMa Formate für Dateien und Pfade? Java Basics - Anfänger-Themen 1
O Datei in mehrere kleine Dateien umwandeln Java Basics - Anfänger-Themen 47
L Richtige Reihenfolge der Dateien Java Basics - Anfänger-Themen 5
CptK Datentypen Text Dateien einlesen Java Basics - Anfänger-Themen 3
J Logging erzeugt zwei dateien.... Java Basics - Anfänger-Themen 7
A Dateien Verschieben Java Basics - Anfänger-Themen 1
M Mehre Dateien parallel kopieren mit Multithreading Java Basics - Anfänger-Themen 8
C Methoden Dateien im Ordner anzeigen Java Basics - Anfänger-Themen 12
J Java-Dateien lassen sich nicht editieren Java Basics - Anfänger-Themen 46
E FTP Dateien hochladen Java Basics - Anfänger-Themen 3
J Probleme beim schreiben von Dateien Java Basics - Anfänger-Themen 5
Korvinus Vergleichen von 2 csv-Dateien Java Basics - Anfänger-Themen 2
I Texte mit Absätzen in Dateien speichern und auslesen Java Basics - Anfänger-Themen 1
M "substring()" mit Dateien und Pfadangaben Java Basics - Anfänger-Themen 5
Voreck Jar Dateien Standart programm ändern Java Basics - Anfänger-Themen 12
K Dateien aus Source-Package verwenden Java Basics - Anfänger-Themen 10
B Dateien aus dem "resource" - Folder kopieren in Verzeichnis Java Basics - Anfänger-Themen 9
B Kopieren von Dateien mit Adminberechtigungen Java Basics - Anfänger-Themen 14
F Threads ftp4j, viele Dateien upload Java Basics - Anfänger-Themen 5
P Einen Ordner mit Dateien hochladen [FTP] Java Basics - Anfänger-Themen 2
X Dateien direkt hintereinander schreiben, Dateiname Java Basics - Anfänger-Themen 25
G Messwerte in 2 Dateien schreiben Java Basics - Anfänger-Themen 20
C Verarbeitung von sehr großen Dateien Java Basics - Anfänger-Themen 52
F Input/Output Dateien lesen/schreiben Java Basics - Anfänger-Themen 1
V Mehrere Dateien aus JFileChooser in eine ArrayList speichern Java Basics - Anfänger-Themen 2
K Dateien lesen | IndexOutOfBoundsException Java Basics - Anfänger-Themen 2
T Classpath Problem mit dem auslesen von Text-Dateien (Pfad) Java Basics - Anfänger-Themen 3
A attach source: Zusammenhang zwischen JAR und .class/.java Dateien? Java Basics - Anfänger-Themen 2
T .jar Datei als Ordner benutzen/ Dateien aus .jar Datei auslesen Java Basics - Anfänger-Themen 3
C Klassen Class Files nachladen (mehrer .jar Dateien) Java Basics - Anfänger-Themen 2
Bluedaishi for schleife um Dateien wieder zusammen zu fügen Java Basics - Anfänger-Themen 11
S Resourcen-Dateien im Jar-File verfügbar machen (Intellij 14) Java Basics - Anfänger-Themen 14
J Dateien für anderen User "mitgeben" Java Basics - Anfänger-Themen 1
S Dateien mit Java verschieben Java Basics - Anfänger-Themen 6
A Heap Space Error bei rekursiver Suche in Dateien trotz nur einer Zeile im Speicher Java Basics - Anfänger-Themen 26
E Dateien werden nicht gelöscht Java Basics - Anfänger-Themen 10
S Class Dateien decompilieren Java Basics - Anfänger-Themen 4
T Fehler beim Schreiben in Dateien! Java Basics - Anfänger-Themen 4
Bluedaishi Dateien Lassen sich unter windows nicht löschen Java Basics - Anfänger-Themen 8
Z Mehrere XML-Dateien zu einer zusammenfügen Java Basics - Anfänger-Themen 3
K JAR Dateien einbinden - funkt nicht wie es sollte... Java Basics - Anfänger-Themen 22
M Threads nio Dateien kopieren, Threads und Gui Java Basics - Anfänger-Themen 0
J *.sql Dateien in Java Java Basics - Anfänger-Themen 1
P Dateien im Ordner auflisten. Java Basics - Anfänger-Themen 3
P Compiler-Fehler .java Dateien kompilieren und .class Dateien zur .jar Java Basics - Anfänger-Themen 4
S Daten aus anderen Dateien in neue Datei einlesen Java Basics - Anfänger-Themen 3
M Input/Output Arbeiten mit extrem vielen Dateien Java Basics - Anfänger-Themen 8
R File chooser Dateien in frame anzeigen lassen Java Basics - Anfänger-Themen 5
N tar-Dateien Java Basics - Anfänger-Themen 6
B Methoden Dateien konvertieren Java Basics - Anfänger-Themen 3
L Dateien speichern/auslesen Java Basics - Anfänger-Themen 5
M Input/Output Probleme beim Parsen von CSV und TXT Dateien Java Basics - Anfänger-Themen 7
P Wiedereinstieg und kann keine Dateien mehr öffnen... Java Basics - Anfänger-Themen 13
F Classpath Dateien einbinden und Classpath durchsuchen Java Basics - Anfänger-Themen 2
N Java Programm zum Suchen und Ersetzen von Text Dateien Java Basics - Anfänger-Themen 10
S Dateien/LinkedList/StringBuffer - SOrtierung klappt nicht so ganz Java Basics - Anfänger-Themen 2
U Best Practice Nicht-permanente Links auf Dateien Java Basics - Anfänger-Themen 5
B In welchem (Default) Pfad erstellt Java Dateien? Java Basics - Anfänger-Themen 4
I Methoden zum lesen und speichern von Dateien Java Basics - Anfänger-Themen 2
B .ut dateien ignorieren und fortsetzen Java Basics - Anfänger-Themen 9
R Ressourcen in JAR-Dateien Java Basics - Anfänger-Themen 2
J jar Dateien global erreichbar machen Java Basics - Anfänger-Themen 3
L Zusammenführen mehrerer .txt Dateien Java Basics - Anfänger-Themen 4
M Dateien erstellen/ bearbeiten/ lesen Java Basics - Anfänger-Themen 9
S Dateien in RAM kopieren und ausführen? Java Basics - Anfänger-Themen 4
O Java Dateien verschlüsseln? Java Basics - Anfänger-Themen 22
K Unterschied zwischen Jar, war und ear Dateien Java Basics - Anfänger-Themen 3
B Dateien kopieren, entpacken, XML auslesen! Java Basics - Anfänger-Themen 7
B Dateien Verschieben! Java Basics - Anfänger-Themen 8
B ältere Dateien verschieben Java Basics - Anfänger-Themen 3
G Erste Schritte Nach bestimmten Dateien suchen und dann in die Registry schreiben. Java Basics - Anfänger-Themen 6
J Laden von Dateien Java Basics - Anfänger-Themen 19
I Xml dateien zusammenfügen Java Basics - Anfänger-Themen 12
I Dateien in Ordner und Unterordner durchsuchen Java Basics - Anfänger-Themen 18
J Markierte Einträge (Dateien) in JList sollen in einen anderen Ordner verschoben werden. Java Basics - Anfänger-Themen 12
N Input/Output Große Dateien schnell Speichern/auslesen Java Basics - Anfänger-Themen 16
L Klassen Ich kann keine .jar Dateien mehr öffnen Java Basics - Anfänger-Themen 4
T Java Projekt als runnable jar file exportieren inklusive csv Dateien Java Basics - Anfänger-Themen 4
B Ordner in jar dateien einfügen Java Basics - Anfänger-Themen 4
FrozeTee .java Dateien unter Windows 7 werden nicht angezeigt Java Basics - Anfänger-Themen 7
D .jar Dateien hochladen Java Basics - Anfänger-Themen 13

Ähnliche Java Themen

Neue Themen


Oben