PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Dateitransfer im Netzwerk


ZeroJump
17.02.2002, 13:01
Hallo, ich hatte vor ein sehr simples Server/Client-Paar zu schreiben, das folgende Aufgabe haben sollte:

Der Client fordert beim Server per Konsoleneingabe eine Datei an, der Server sollte diese an den Client übertragen. Soweit so gut, bei der Übertragung wird einiges durcheinandergeschmissen, beispielsweise, wenn ich ein Bild übertrage im JPG-Format, so habe ich hinterher viele bunte dicke Streifen darin >> fehlerhafte Übertragung. Außerdem dauert es ewig lange, da ich immer nur ein Zeichen aus der Datei lese und in den Outputstream des Servers schreibe.

Wie kann ich eine Datei über das Netzwerk schnell und korrekt übertragen?

Habe dazu auch keine passenden Tutorials gefunden,

ZJ


Fragger
17.02.2002, 23:02
hi,

ich würde so vorgehen, wenn du weisst das deine datei nicht grösser als MAX int ist, dann würde ich ein array definieren das so gross ist wie die datei, dann die ganze datei einlesen, und statt byte für byte an den client zu schicken, das ganze byte array verschicken.
also:
byte[] byt = new byte[(int) file.length()];
DataInputStream dis = new DataInputStream(new FileInputStream(file));
dis.readFully(byt);
dis.close();
//jetzt hast du die ganze datei in dem byte array
socket.write(byt);
socket.flush(); //ganz wichtig damit der stream vollkommen entleert wird.
/*
socket.close();
ODER
andere operationen auf dem socket
*/

gruesse, fragger
p.s. wenn deine datei nicht in ein byte array reinpasst,
da zu gross, dann musst du halt entsprechende
routinen schreiben die deine datei in mehreren byte
array paketen verschicken.

ZeroJump
19.02.2002, 14:18
Hallo, die gleiche Idee hatte ich auch ungefähr, aber meine Dateien sind auf jeden Fall größer als ein "int" fassen kann. Mir fehlt beim coden eindeutig noch die Erfahrung, deshalb tue ich mich ein wenig schwer mit der Routine, könntest Du mir da auch noch helfen, mit Hilfe eines kleinen Codebeispiels?

thx, Salke!

Fragger
19.02.2002, 16:55
hi,

ich meinte nicht das du eine datei in ein int packen solltest, sondern die grösse deiner datei. der max wert den ein integer darstellen kann ist, grösser als 2 gb,
willst du wirklich eine datei solcher grösser über das netzwerk schicken? ich glaueb du hast mich einfach nicht richtig verstanden. werde dir heute abend ein bsp. posten, so ab 19 uhr.

gruesse, ercano

ZeroJump
19.02.2002, 17:41
Doch, doch, ich hab Dich schon richtig verstanden, vielleicht hab ich mich ja einfach nur ungeschickt ausgedrückt! :-)


Was anderes:

Wenn ich das Array über den Output-Stream des Sockets geschickt habe, wie lese ich es dann auf der anderen Seite wieder ein?

ZJ

Fragger
19.02.2002, 22:23
hi,

wenn du über das netzwerk kommunizierst
solltest du dir im grunde schon vorab gedanken
über ein protokoll machen, nein ich meine jetzt nicht
tcp/ip oder so, sondern ein protokoll wie deine
kommunikation verläuft, ein einfaches beispiel
ist z.B. bevor du daten schreibst, schreibst du die
länge der daten, also wenn du ein byte array mit
der grösse von 8000 bytes schreiben willst
dann schreibst du als erstes 8000 in deinen stream
danach schreibst du die daten. die andere seite
die auf die daten wartet liest immer als erstes ein int
ein, wenn du dieses int eingelesen hast, kannst du
ein byte array erzeugen was der grösse des int´s
entspricht und dann dieses einlesen.
Übrigens die Klasse DataInputStream hat eine
mehode, readFully(byte[] byt) die soviel daten von
einem stream liest, wie die grösse des byte
array. wenn natrülcih nur 4000 bytes zur verfügung gestanden haben, dann liest readFully auch nur
4000 bytes ein. als Rückgabewert liefert dir readFully
eine int zahl, die den eingelesen bytes entspricht.

sender:
byte[] byt = new byte[8000];
DataOutputStream dos = new DataOutputStream(socket.getOuputStream());
dos.writeInt(byt.length);
dos.flush();
dos.write(byt);
dos.flush();

empfänger:
DataInputStream dis = new DataInputStream(socket.getInputStream());
int size = dis.readInt();
byte[] byt = new byte[size];
dis.readFully(byt);

so das wars,
gruesse, fragger

ZeroJump
20.02.2002, 15:46
ich bin gestern schon alleine auf die Idee gekommen readFully() zu benutzen auf der Empfängerseite. Damit geht die Sache jetzt einigermaßen schnell.

Trotzdem vielen Dank.

Jetzt noch was anderes, ist es prinzipiell möglich, ein Java-Programm komplett im Hintergrund ablaufen zu lassen, also auch ohne Konsole?

Fragger
21.02.2002, 08:47
hi,

benutze statt den java befhel den javaw
befehl. dann startet deine Appliaktion als
Windows Appliaktion, also ohne Konsole.
bedenke aber das du dann keine System.out
und System.err mehr sehen kannst. diese solltest
du dann in ein eigenes fenster umleiten.

gruesse, fragger

ZeroJump
22.02.2002, 22:47
Hehe, und schon weiss ich, warum man ein Protokoll nutzen sollte und nicht einfach ein Riesen-Array schickt. Wollte heute mal so 46MB übertragen und was war: OutOfMemoryException (oder Error, weiss nicht mehr)

Allerdings macht mir das wieder Probleme: Ich brauch eine Schleife, die meine Datei immer in handliche, sagen wir 10000Byte-Pakete zerlegt, also 10000Bytes in ein Array schreibt und losschickt. Die nächsten 10000Bytes müssen nun aber logischerweise in der Datei aber auch erst ab Position/Offset 10000 gelesen werden. Dazu wollte ich die Methode read(byte[] byte, int offset, int length) nutzen, da ich die Dokumentation so verstanden hab, dass das Offset die Stelle der Datei beschreibt ab der ich Lesen möchte. Das alles ist ziemlich schwierig (für mich), irgendwelche ideen?

ZJ

PS: Das mit der Standard-Ausgabe is kein Problem, da mein Server alle Vorgänge in einer Textdatei protokolliert, aber keine sonstigen Ausgaben hat.

Fragger
23.02.2002, 10:17
hi,

du hast di doku falsch verstanden.
das (byte byt, int offset, int length)
besagt, das das zu schreibende an der
stelle offset, mit der länge length in das array byt
beschrieben werden soll.
wegen dem einlesen, du kannst in einer
schleife einlesen, bsp.

versender:
byte[] byt = new byte[8192];
int readed = 0;
while((readed = fileInputStream.read(byt)) != -1)
{
socketOutputStream.write(byt, 0, readed);
socketOutputStream.flush();
}

empfänger:
byte[] byt = new byte[8192];
int readed = 0;
while((readed = socketInputStream.read(byt)) != -1)
{
fileOutputStream.write(byt, 0, readed);
fileOutputStream.flush();
}

gruesse, fragger

ZeroJump
23.02.2002, 14:44
Original von Fragger

versender:
byte[] byt = new byte[8192];
int readed = 0;
while((readed = fileInputStream.read(byt)) != -1)
{
socketOutputStream.write(byt, 0, readed);
socketOutputStream.flush();
}

empfänger:
byte[] byt = new byte[8192];
int readed = 0;
while((readed = socketInputStream.read(byt)) != -1)
{
fileOutputStream.write(byt, 0, readed);
fileOutputStream.flush();
}



Das funktioniert so nicht, da ich auf der Client-Seite in einer Endlos-Schleife hänge. Auf der Server-Seite wird die Datei zwar vollständig geschickt, auf der Client-Seite auch vollständig geschrieben, aber ich komme nicht aus der Einlese-Schleife heraus.

Gruß ZJ

Fragger
23.02.2002, 19:38
hi
meinst du jetzt das das was ich dir geschrieben
habe nicht funzt, oder was anderes, wenn ja
dann erkläre es bitte kurz
gruesse, fragger

ZeroJump
23.02.2002, 21:22
Ich meine Deine Lösung, auf der Empfängerseite lande ich so in einer Endlos-Einlese-Schleife!

Fragger
24.02.2002, 01:48
hi,
klar du musst die verbindung nach der datei schliessen
wenn du sie weiter benutzen willst, solltest du dir ein
protokoll überlegen mit dem du kommunizierst.
du könntest die grösse der datei vorher schicken
und deine schleife könnte solange laufen, bis ein zähler
der immer mit den eingelesenen bytes länge aufaddiert
wird, die gleiche grösse wie die datei grösse hat.

gruesse, fragger

Bibolorean
24.02.2002, 02:10
*versuchzuhelfen*

nur noch sone anmerkung.. in QBasic gibt´s das EOF signal.. ich weiss zwar nich, ob man das senden kan, aber vielleich gibt´s ja sowas auch in Java??

Greetz Bìbòlorean

Fragger
25.02.2002, 08:17
hi,

das EOF wird hier in diesem fall mit der anzahl gelesener
bytes = -1 erkennbar gemacht.
d.h. du liest solange ein, bis du -1 als einegelsene
bytes zurück bekommst, dann weisst du das ende
ist erreicht.
aber das könnte ab und zu zu fehlern führen, deswegen
ist es besser sich immer vorab ein eigenes protokoll
zu überlegen. ist sowieso muss, wenn man prof.
software erstellt :)

gruesse, fragger