Socket Outputstream - chunks groeße bestimmen.

Evilsadness

Mitglied
Hayyy!!!

Bin gerade total am Verzweifeln!!!

Ich programmiere gerade ein Server/Client, die per TCP eine Datei sendet.

Ich habe es schon so weit geschafft, dass die untereinander kommunizieren etc.
So.. nun an den Punkt wo ich nicht weiter komme:
Der Client hat ganz am Anfang eine Nachricht geschickt, welche Datei er haben will und wie groß die Pakete sein sollen(Chunks). Der Server hat die Nachricht erhalten, speichert den Wert und sendet ein OK zurück.
Nun Soll der Client solange anfragen(GET) , bis die Datei vom Server in Speicherblöcken vollständig geschickt wurden ist.
Ich weiß ich muss das mit Outputstream und Inputstream machen, jedoch bekomme ich das nicht hin. =/

Also wie kann ich durch schleifen das so hinbekommen, dass der Client solange mit GET anfragt und der Server solange die Get anfragen mit Chunks-blöcken beantwortet, bis die Datei abgearbeitet ist?
 

eMmiE

Bekanntes Mitglied
Also:
Der Client will Pakete der Größe x haben
und hat dazu einen Dateinamen angegeben

Jetzt muss der Server doch erstmal die Datei in Pakete zerteilen (wie, das weißt du hoffe ich, ich habe nämlich keine Ahnung, außer mit Strings oder binärem zu arbeiten)
Dazu stellst du am Besten einen Data[] zur Verfügung und initialisierst den mit den Dateidaten.
Dann sendest du das OK

Beim Client müsste das dann so aussehen, dass der entweder einen Array der selben Länge hat (weiß der, wie groß die Datei ist? -> mitteilen) oder eine ArrayList (würde ich in dem Zusammenhang nicht nehmen, weil das sau lange (mehrere ms) dauert, bis immer wieder ein neuer Speicherplatz angefordert wurde und die ArrayList auch überladen werden könnte (-> max. Dateigröße festlegen?))

Code:
//Client:

void getIt() {
sende(dateiname,paketgröße)
long zeit = System.currentTimeMillis();
while (!server.getOk() || System.currentTimeMillis()-zeit < 30000) {
  //warten
}

if (System.currentTimeMillis()-zeit > 30000) {
  //timeout, mach was du für richtig hältst
} else {
  int paketanzahl = (int)(server.getDateigröße(dateiname) / paketgröße+0.5/*<- wegen demRunden*/)
  Data[] dateistücke = new Data[paketanzahl];
  for (int i = 0;i < paketanzahl;i++) {     
     dateistücke[i] = server.getPaket(i);
  }
}
}

Wäre jetzt mein Ansatz

Falls das Andere mit den Streams deine Frage war, dann würde ich sagen, dass du die Methoden ungefähr so schreiben müsstest:

Code:
Data getPaket(i) {
  InputStream in = new InputStream(server.getOutputStream());
  server.sendePaket();
  char[] inhalt = new char[(int)(server.getDateigröße()/Paketanzahl+0.5)];
  in.read(inhalt);
  in.close();
}

long getDateigröße(String dateiname) {
  return (new File(root.getAbsolutePath()+dateiname)).length;
}

Hoffe ich konnte helfen :)

Gruß eMmiE
 

Evilsadness

Mitglied
danke auf jeden Fall schon mal !!!! Aber das ist nicht das was ich haben will =/. Da habe ich mich nicht genau ausgedrueckt.
Also...

1-Der Client weiß nicht wie groß die Datei ist.
->da würde ich einfach ein großes byte Array nehmen.

2-Der Client sendet nun iteriert Anfragen der Art GET an den Server.

3-Der Server sendetdaraufhin die Pakete vereinbarter Groeoe zurueuck. Diese werden mit einem Pre x DATA;<data>versehen ( <data> sind die transferierten Daten). Die Daten werden durch den Client gelesenund in einer Datei gespeichert. Da die Groeßeoe der Chunks bei den GET Nachrichten nicht mitgeschickt wird, muss im Server eine Zuordnung dieses Wertes mit gespeichert werden.

Ich sende mal mein Code mit passende Kommentare:. Viellecht ein bisschen durcheinander weil ich viel herumprobiert habe:

Server:

Java:
public class Server {

	public final static int SOCKET_PORT = 8999;
	public final static String PFAD = "c:/temp/";

	public static void main(String[] args) throws IOException {

		FileInputStream fileIn = null;
		BufferedInputStream bis = null;
		OutputStream outps = null;
		ServerSocket servsock = null;
		Socket sock = null;
		Scanner in = null;
		PrintWriter out = null;
		try {
			servsock = new ServerSocket(SOCKET_PORT);
			while (true) {
				System.out.println("Waiting...");
				try {
					sock = servsock.accept();

					System.out.println("Accepted connection : " + sock);

					// INITX
					in = new Scanner(sock.getInputStream());
					out = new PrintWriter(sock.getOutputStream(), true);
					String requestINITX = in.nextLine();
					String[] received = requestINITX.split(";");
					// received[0] = INITX - received[1] = Chunk-size -
					// received[2] = Datei
					String angefordereDatei = received[2];

					// if = True = OK
					// else = ERROR
					File datei = new File(PFAD + angefordereDatei);
					if (datei.exists()) {

						out.println("OK" + ";");
						double dateigroeße = datei.length();
						int chunk = Integer.parseInt(received[1]);
						int i = 0;
						fileIn = new FileInputStream(datei);
						byte[] fileContent = new byte[(int) dateigroeße];
						fileIn.read(fileContent);
						outps = sock.getOutputStream();
						while (i <= dateigroeße) {
							//erwartet eine GET Nachricht
							String requestGET = in.nextLine();
							if ((requestGET).equals("GET")) {
								
								//sendet nun die Nachricht: 
								// DATA + chunkgroßes Paket

								i += chunk;
							}
							//Falls alles Versendet wurde:
							// sendet er FINISH

						}


						System.out.println("Done.");

					} else {
						out.println("ERROR" + ";" + "Datei nicht vorhanden");

					}

				} finally {
					if (bis != null)
						bis.close();
					if (out != null)
						out.close();
					if (sock != null)
						sock.close();
					if (in != null)
						in.close();
					if (out != null)
						out.close();
					if (fileIn != null)
						fileIn.close();
				}
			}
		} finally {
			if (servsock != null)
				servsock.close();
		}
	}
}

Client:

Java:
public class Client {

	public final static int SOCKET_PORT = 8999;
	public final static String SERVER = "127.0.0.1"; // localhost
	public final static String FILE_TO_RECEIVED = "c:/temp/bb.txt";
	public final static String FILE_REQUEST = "aa.txt";
	public final static int CHUNK_SIZE = 200;
	public final static int FILE_SIZE = 6022386; //Datei muss kleiner sein.

	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		FileOutputStream fos = null;
		BufferedOutputStream output = null;
		Socket sock = null;
		try {
			sock = new Socket(SERVER, SOCKET_PORT);
			System.out.println("Connecting...");
			Scanner in = new Scanner(sock.getInputStream());
			PrintWriter out = new PrintWriter(sock.getOutputStream(), true);

			// Will die Datei haben.INITX;<chunk size>;<filename>
			out.println("INITX" + ";" + CHUNK_SIZE + ";" + FILE_REQUEST);
			String _INITXantwort = in.nextLine();
			String[] received = _INITXantwort.split(";");

			// received[0] = OK
			// ODER - received[0] = ERROR - received[1] = reason

			if ((received[0]).equals("OK")) {

				InputStream input = sock.getInputStream();
				fos = new FileOutputStream(FILE_TO_RECEIVED);
				output = new BufferedOutputStream(fos);
				byte[] fileArray = new byte[FILE_SIZE];
				String finish = "";
				while (!(finish.equals("FINISH")) || !(finish.equals("ERROR"))) {
					out.println("GET");
					//Nachricht empfangen <-- Hier brauch ich Hilfe
					//Sendet der Server eine Nachricht mit DATA;<Dateiinhalt>
					// filArray+Dateiinhalt
					//Sendet der Server eine Nachricht mit FINISH
					// finish = FINISH
				}

			} else {
				System.out.println(received[0] + ":  " + received[1]);
			}

		} finally {
			if (fos != null)
				fos.close();
			if (output != null)
				output.close();
			if (sock != null)
				sock.close();
		}
	}

}


Der Server hat die Datei bereits in einem ByteArray:
byte[] fileContent = new byte[(int) dateigroeße];
ich weiß aber nicht wie ich davon ich die ersten (Wenn Chunk nun 200 währen) 200 Chunks los schicke und der Client diese Chunks im Array speichert und dies am Ende richtig in der Datei schreibt.

Hier mal ein Bild von meinem Vorhaben:
 

Anhänge

  • TCP.jpg
    TCP.jpg
    49,9 KB · Aufrufe: 40

wef34fewrg

Aktives Mitglied
Darf ich zu Beginn fragen wieso du das so machen willst? Ist einfach nur eine Interessensfrage. Ist für meinen Geschmack halt etwas unschön, wenn du in einem Protokoll, dass dir alles vorkauft und du das quazi unterwandern willst mir GET Anfragen arbeiten möchtest.


Es wäre sinnvoll, wenn der Client zu Beginn mit der OK Bestätigung die Größe der Datei mitgeliefert bekommen würde (übrigens datei.length() liefert long. Keine Notwendigkeit das in ein double zu speichern). Auf Clientseite kannst du natürlich ein sehr großes ByteArray anlegen, aber das ist äußerst unschön, zumal es eben doch mal vorkommen kann, dass die Datei größer ist und was dann? Dann knallts im Programm.
Eine Alternative wäre, dass du auf der Clientseite den empfangenen Strom direkt in einen Fileoutputstream schreibst, anstatt ihn in einem ByteArray zwischen zu speichern. Bei Filestreams solltest du übrigens mit BufferedInput/Outputstreams arbeiten.

Zum eigentlichen Problem. Du kannst auf Serverseite mit einem Bufferedoutputstream arbeiten, in dem du den Socketoutputstream kapselst.
Die Klasse BufferedOutputstream hat die Methode
Code:
public void write(byte[] b, int off, int len)
Du kannst das Byte Array direkt nutzen und es in einer Schleife durchlaufen. off ist dabei dein Startwert, der jedes Mal mit chunk aufaddiert wird und die Länge versteht sich von selbst. Du musst nur darauf achten, dass du am Schluss nicht eine ArrayOutOfBoundException auflöst, weil die Dateilänger dividiert durch den chunk höchstwahrscheinlich einen Rest enthält.
Nach der write Methode, muss dann public void flush() aufgerufen werden, damit du sicher gehen kannst, dass alle bytes durch den Outputstream gejagt werden.

Danach wirds etwas tricky.
Meine Lösung wäre, anstelle eines Scanners einen InputStreamReader zu nutzen, der zeichenweise aus einem Strom ließt. Der große Unterschied ist, dass der InputStreamReader eine Methode read besitzt, die blockiert, bis der Client das GET geschickt hat bzw. der Strom zu Ende ist.
Wenn dir das zu doof ist, dann musst du eine andere Möglichkeit finden am Ende der Schleife auf das neue GET zu warten, damit im nächste Durchlauf die
Code:
public void write(byte[] b, int off, int len)
aufgerufen wird.

Die Clientseite kann ähnlich funktionieren.

Mit BufferedInputStream kannst du entweder in einer while Schleife die read Methode durchlaufen, bis der Strom zu Ende ist bzw. die chunk Größe an gesendeten Bytes angekommen ist und die Schleife dann abbrechen, oder du nutzt hier das Gegenstück zu der oben gezeigten write Methode
Code:
public int read(byte[] b, int off, int len)
Wenn du ein ByteArray erstellst, dass die Größe des chunks hat, dann füllt Java dir das Array, welches du dann für deine Zwischenspeicherung bzw. den Fileoutputstream (oben erwähnt) verwenden kannst.

Danach musst du die GET Anfrage schicken. Wie du das umsetzt, musst du selber wissen. Hier würde ich eben den OutputStreamWriter nehmen, der den Outputstream des Socket kapselt und dir eine write Methode zur Verfügung stellt, der du einen String übergeben kannst.


Ich weiß natürlich nicht, ob das jetzt deinen Vorstellungen entspricht und hoffe das war verständlich.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T OutputStream kommt nicht an Netzwerkprogrammierung 18
L Socket Wie kann ich checken ob ein User eine Nachricht per Outputstream an den Server gesendet hat? Netzwerkprogrammierung 1
S FTP OutputStream Timed out Netzwerkprogrammierung 2
D Socket Socket OutputStream leeren? Netzwerkprogrammierung 3
Seikuassi Socket CipherInput/OutputStream empfängt nichts Netzwerkprogrammierung 23
C Inhalt einer .JPG Datei in einen OutputStream schreiben? Netzwerkprogrammierung 10
T Socket ObjectIn/OutputStream Netzwerkprogrammierung 3
A Socket BufferedReader.readLine() blockiert bis ein im Socket OutputStream was gesendet wird ... Netzwerkprogrammierung 9
M Socket InputStream sendet ausgaben von OutputStream zurück Netzwerkprogrammierung 2
D Inputstream to Outputstream Netzwerkprogrammierung 3
T Outputstream Byte-Array senden Netzwerkprogrammierung 2
H Input-/OutputStream Frage Netzwerkprogrammierung 6
O Mehrere Datei per DataInput/OutputStream über Socket Netzwerkprogrammierung 12
P Probleme mit OutputStream Netzwerkprogrammierung 7
M Verbindung über Proxy// Problem mit Outputstream bei URLConn Netzwerkprogrammierung 5
PAX Outputstream von anderem Thread verwenden lassen Netzwerkprogrammierung 5
T Filter für Input UND OutputStream Netzwerkprogrammierung 4
Y Inhalt aus Textfield in OutputStream packen Netzwerkprogrammierung 4
bummerland Cookies über OutputStream senden Netzwerkprogrammierung 2

Ähnliche Java Themen

Neue Themen


Oben