# Datei über Socket schreiben und Ereignis lesen



## Computerbabalul (4. Jul 2012)

Hallo Ihr lieben

Ich habe da ein kleines Problem und bräuchte mal eure Hilfe!

Ich muss Dateien (> 2 GB) via Socket an einen Server senden.
Dazu gibt es auch eine kurze Beschreibung, (siehe weiter unten in Blau).

Wie muss der Client aussehen um den Anforderungen des Servers zu entsprechen?
Um es gleich vor weg zu nehmen, ich bin kein Java Experte, ich programmiere
eigentlich in Pascal. Allerdings muss ich dieses Projekt leider in Java machen.

Wenn mir jemand ein kleines Beispiel geben könnte, wäre ich dankbar.
Ich habe einige Beispiele hier aus dem Forum getestet, da wir die Datei
allerdings in einem Rutsch als Stream gesendet, das Funktioniert sogar.
Allerdings bekomme ich da die Antworten vom Server nicht mit, da ja laut Protokoll Blockweise
gesendet werden soll, und nach dem ersten Block kommt ja bereits eine Antwort vom Server.

Vorab vielen Dank für´s Lesen!

Gruß Baba

*Socket Communication Protocol *

*Messages sequence 
Once the client initiates connection with the Server, 5 steps can be identified: *

1. The client send the job’s first block of data to Server, (size of block does not 
matter). 

Client (send) Server (receive) First block of job 

2. The client receives back the job index message, from Server (on the same socket). 

Client (receive) Server (send) Job Index 

3. Client sends the rest of the job’s data (if any). 

Client (send) Server (receive) Block of job... Block of job ...Block of job...

4. After Server finished receiving the job the client receive a job status message, from 
Server (on the same socket). It is not mandatory to get this message, and the client 
may skip this phase. 

Client (receive) Server (send)  Job Status 

5. Client closes handle. 
Note: This step is needed to enable future successful connections. 


*5.3 Client connection diagram *
open connection 
send 1st job’s block 
receive job index message 
send block of data 
receive job status message 
close handle 

*5.4 Messages structure *
The Server returns two messages while loading jobs. 
Each of these messages returned consists of 3 segments: 

Message type Message length Message contents 
Segment 1: a 4-byte integer representing the Message type. 
Message type could be 1 of 2: 

Integer value Message Type 
0 Job index in Server imaging system. 
1 Job status 

Segment 2: a 4-byte integer representing message length, in bytes. 

Segment 3: The Message itself. Its length is specified in the second segment. If the message type is 
Job Index then the message is an integer representing the new job index on TS. If the message type is 
job status, then the integer value could be one of: 

Integer value Job‘s status 
4 Job is partially loaded. 
5 Job successfully loaded. 
6 The user aborted job loading. 
7 Job’s loading ended with errors.


----------



## Xeonkryptos (4. Jul 2012)

Ohne die Beschreibung/Erklärung, die du hinzugefügt hast, durchgelesen zu haben, liegt es am Server, die Dateien "blockweise" zu verschicken. Der Server zerlegt einfach die Datei und schickt sie stückweise an den Client. Nach jedem fertigen Block wird statt dem nächsten Block einfach die Antwort vom Server geschickt und dann folgt der nächste Block an den Client.

Du musst einfach die Datei/en in einheitliche größen "zerlegen" und diese dann stückweise an den Client verschicken.


----------



## Computerbabalul (4. Jul 2012)

> Ohne die Beschreibung/Erklärung, die du hinzugefügt hast, durchgelesen zu haben, liegt es am Server, die Dateien "blockweise" zu verschicken. Der Server zerlegt einfach die Datei und schickt sie stückweise an den Client. Nach jedem fertigen Block wird statt dem nächsten Block einfach die Antwort vom Server geschickt und dann folgt der nächste Block an den Client.
> 
> Du musst einfach die Datei/en in einheitliche größen "zerlegen" und diese dann stückweise an den Client verschicken.



Hallo und Danke für deine Antwort!

Nein, da hättest du besser doch einmal gelesen. Der Server empfängt nur die Daten und existiert bereits.
Es ist eine fertige Software. Was ich machen muss, ist im eine Datei zu senden und zwar so:

Ich sende ihm den ersten Block der Datei, dabei ist die Blockgröße wohl egal.
Darauf hin bekomme ich vom Server eine Antwort unter welcher Dateinummer er den Job verwaltet.
Dann sende ich den Rest der Datei. Nach dem die Datei vollständig übertragen wurde,
bekomme ich vom Server noch eine Antwort ob der Job erfolgreich importiert wurde.

Das die Datei zerlegt werden muss, ist mir auch schon klar, habe auch schon einige Beispiele mit ByteArray ausprobiert,
bekomme es aber nicht hin, da ich von Java wirklich so gut wie keine Ahnung habe. Ich arbeite mit Pascal, und
dort habe ich auch schon einen Funktionierenden Client Programmiert, dieser läuft allerdings nur auf Windows.
Ich benötige aber den Client Plattform unabhängig, daher Java. Ich bräuchte nur ein Beispiel wie das Senden der Datei
in Java auszusehen hat. Es gibt schon einige Beispiele im Netz die Funktionieren aber so leider für mich nicht,
da die Datei als Stream komplett gesendet wird.

Trotzdem Danke für die Antwort!

Gruß Frank


----------



## KingOfExceptions (4. Jul 2012)

Ich hatte grad nicht die Zeit, mir alles durchzulesen, aber das werde ich morgen nachholen. 
Außerdem hatte ich schon Mal so ein ähnliches Programm geschrieben, das poste ich hier morgen.
Grüße


----------



## Computerbabalul (4. Jul 2012)

> Ich hatte grad nicht die Zeit, mir alles durchzulesen, aber das werde ich morgen nachholen.
> Außerdem hatte ich schon Mal so ein ähnliches Programm geschrieben, das poste ich hier morgen.
> Grüße



OK, vielen Dank und gute Nacht...


----------



## KingOfExceptions (5. Jul 2012)

So wie versprochen hier mal ein Programm zum Upload von Dateien auf einen Server.

Client:

```
package SendFiles;

import java.io.*;
import java.net.*;

import javax.swing.JOptionPane;

/**
 * @author KingOfExceptions
 * Client who uploads files
 */
public class UploaderFile
{
    Socket               sock;
    BufferedOutputStream buffout;
    File                 chosenFile;
    FileFenster          fileFenster = new FileFenster();
    FileInputStream      input;
    BufferedInputStream  buffinput;
    long timeStart;
    long timeEnd;
    static String ipAdress;
    
    public static void main(String[]args) throws IOException, InterruptedException
    {
        ipAdress=JOptionPane.showInputDialog("IP-Adress Server:");
        UploaderFile uploader = new UploaderFile();
        uploader.doConnection();
        
        uploader.sendFile();
    }
    
    public void doConnection() throws IOException
    {
        timeStart=System.currentTimeMillis();
        
        sock = new Socket(ipAdress, 12345); //PATRICK PC --> nur 'localhost' geht
        InetAddress adress=sock.getInetAddress();
        
        System.out.println(InetAddress.getLocalHost());
        System.out.println(adress.isReachable(10000));
        System.out.println(adress.getAddress());
        
        System.out.println("Connected");
        
        chosenFile = fileFenster.getFile();
        
        buffout = new BufferedOutputStream(sock.getOutputStream());
        input = new FileInputStream(chosenFile);
        buffinput = new BufferedInputStream(input);
        
        System.out.println("Streams done");
    }
    
    public void sendFile() throws IOException, InterruptedException
    {
        byte[] array = new byte[(int) chosenFile.length()];
        System.out.println(chosenFile.length());
        
        buffinput.read(array, 0, array.length);
        
        buffout.write(array);
        buffout.flush();
        
        System.out.println("Gesendet");
        // close all streams
        buffout.close();
        input.close();
        buffinput.close();
        sock.close();
        timeEnd=System.currentTimeMillis();
        System.out.println("Time start: "+timeStart);
        System.out.println("Time end: "+timeEnd);
        System.out.println("Difference: "+(timeEnd-timeStart));
        System.out.println("Time taken in seconds: "+(timeEnd-timeStart)/1000);
        System.exit(0);
    }
    
}
```

FileChooser (gehört auch zu Client):


```
package SendFiles;

import java.io.*;
import javax.swing.*;

public class FileFenster
{
    File file = null;
    
    /**
     * @author KingOfExceptions
     * The file chooser to choose a file to upload
     * This is part of the client
     */
    public FileFenster()
    {
        JFileChooser fc = new JFileChooser();
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.showDialog(fc, "Choose File");
        fc.cancelSelection();
        if (fc.getSelectedFile() != null)
            file = fc.getSelectedFile();
        else
        {
            JOptionPane.showMessageDialog(null, "The file is null, system closes");
            System.exit(-1);
        }
        
        if(fc.getSelectedFile().length()>26587136)
        {
            JOptionPane.showMessageDialog(null, "The file is too big, system closes");
            System.exit(-1);
        }
    }
    
    public File getFile()
    {
        return file;
    }
    
}
```

Server (zum empfangen der Dateien):


```
package SendFiles;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JProgressBar;

/**
 * @author Patrick
 *         Server who gets the files.
 */
public class Server
{
    ServerSocket  serversock;
    Socket        sock;
    InputStream   input;
    static Server serv = new Server();
    Thread thr;
    final JProgressBar pbar = new JProgressBar();
    final JFrame fram = new JFrame("Progress");
    
    public static void main(String[] args) throws InterruptedException, IOException
    {
        serv.doStreams();
        serv.getEverything();
    }
    
    public void doStreams() throws IOException
    {
        serversock = new ServerSocket(12345);
        
        System.out.println("Waiting...");
        
        sock = serversock.accept();
        System.out.println("Accepted connection : " + sock);
    }
    
    public void getEverything() throws IOException, InterruptedException
    {
        
        input = sock.getInputStream();
        final byte[] vec = new byte[2000000]; //MAX DATEIGRÖSSE 2GB
        
        int bytesRead = input.read(vec, 0, vec.length);
        int current = bytesRead;
        int zaehler = 0;
        
        thr=new Thread(new Runnable()
        {
            public void run()
            {
                pbar.setMinimum(1);
                pbar.setMaximum(vec.length);
                pbar.setStringPainted(true);
                
                fram.setLocation(500, 0);
                fram.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                fram.setAlwaysOnTop(true);
                fram.add(pbar);
                fram.pack();
                fram.setVisible(true);
            }
        });
        
        thr.start();
        
        
        do
        {
            System.out.println("A");
 
            bytesRead = input.read(vec, current, (vec.length - current));
            zaehler++;
            if (bytesRead >= 0)
                current = current + bytesRead;
            if (zaehler >1500001)
                break;
        }
        while (bytesRead > -1);
        
        System.out.println("B");
        
        OutputStream writer = new FileOutputStream(new File("Datei"));
        
        System.out.println("C");
        
        for (int x=0; x < vec.length; x++)
        {
            writer.write(vec[x]);
            pbar.setValue(x);      
            pbar.repaint();
        }
        
        System.out.println("D");
        fram.dispose();
        
        sock.close();
        input.close();
        serversock.close();
        writer.close();
        JFrame frame = new JFrame(); 
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JLabel("Done!"));
        frame.pack();
        frame.setAlwaysOnTop(true);
        frame.setVisible(true);
        Thread.sleep(1000);
        System.exit(0);
    }
    
}
```

So es ist aber leider nicht so, als ob die Sache jetzt damit gegessen wäre, da dieser 'Uploader' einige Dateitypen nicht unterstützt. So hatte ich leider keinen Erfolg, als ich eine jar verschicken wollte oder ein Video. Ich denke, dass das mit der Codierung zusammenhängt. Vielleicht hat aber hier jemand mehr Ahnung davon als ich. Text (.txt) Dateien sind kein Problem, Bilder (.jpg) auch nicht und sogar Worddateien funktionieren, wenn man die Standartcodierung danach auswählt.

Zu der Aufgabe: Bei meinem Code ist natürlich nicht das ganze Hin-und Herschicken der Informationen drin. Aber dafür hat mein kleines Programm eine JProgressBar miteingebaut *stolz* 

Achso ja, noch etwas: Könnte bitte jemand das Programm mal testen? Mit zwei verschiedenen IPs? Ich hab bis jetzt das ganze nur mit localhost testen können, da ich es nicht geschafft habe, auf meinem Router den Port zu öffnen (müsste glaub ich 22 oder 23 sein, wenn ich mich nicht irre).


----------



## Xeonkryptos (5. Jul 2012)

@KingOfExceptions

In deinem Code sehe ich da keine Pause, in der der Server eine Antwort an den Client zurückschicken kann. Auch bei dir wird die Datei in einem Rutsch weitergeschickt!

Außerdem ist dein Ansatz nicht falsch, aber auch nicht vollständig richtig! Dein Problem, weswegen du keine .jar-Datei oder so normal auf dem Server verwenden kannst ist der, dass du die neue Datei einfach nur "Datei" nennst und nicht "Datei.jar"! Dadurch erkennt Windows diese Datei nicht als .jar-Datei an und du kannst sie nicht durch einen Doppelklick starten! Du müsstest dem Server erst den Namen der Datei zuschicken, damit er dann diesen Namen beim Schreiben auf die Festplatte übernimmt! Dann ist es eine exakte Kopie! Wenn du zum Beispiel 7zip verwendest, um einen Blick in die neu erstellte .jar-Datei zu erstellen, wirst du sehen, dass es genau den Inhalt deiner ausgesuchten .jar-Datei hat!


----------



## KingOfExceptions (5. Jul 2012)

Ja , dass das Programm in einem Rutsch geschickt wird, weiß ich und habe ich meines Wissens auch noch unter meinen Beitrag geschrieben. Es war damals für mich unsinnig so viele Sachen hin und her zu schicken... Das ist ja nur bei dieser speziellen Aufgabe vom TO so.

Ich probiere das mit der .jar gleich mal aus...


----------



## Xeonkryptos (5. Jul 2012)

```
import java.io.*;
import java.net.*;

import javax.swing.JOptionPane;

/**
 * @author KingOfExceptions Client who uploads files
 */
public class UploaderFile {
	private Socket sock;
	private BufferedOutputStream buffout;
	private File chosenFile;
	private FileFenster fileFenster = new FileFenster();
	private FileInputStream input;
	private BufferedInputStream buffinput, buffMessage;
	private long timeStart;
	private long timeEnd;
	private static String ipAdress;

	public static void main(String[] args) throws IOException,
			InterruptedException {
		ipAdress = JOptionPane.showInputDialog("IP-Adress Server:");
		UploaderFile uploader = new UploaderFile();
		uploader.doConnection();

		uploader.sendFile();
	}

	public void doConnection() throws IOException {
		timeStart = System.currentTimeMillis();

		sock = new Socket(ipAdress, 12345); // PATRICK PC --> nur 'localhost'
											// geht
		InetAddress adress = sock.getInetAddress();

		System.out.println(InetAddress.getLocalHost());
		System.out.println(adress.isReachable(10000));
		System.out.println(adress.getAddress());

		System.out.println("Connected");

		chosenFile = fileFenster.getFile();

		buffout = new BufferedOutputStream(sock.getOutputStream());
		input = new FileInputStream(chosenFile);
		buffinput = new BufferedInputStream(input);
		buffMessage = new BufferedInputStream(sock.getInputStream());

		System.out.println("Streams done");
	}

	public void sendFile() throws IOException, InterruptedException {
		/* Größe variierbar */
		int anySize = 1024, msgByteSize = 4;
		byte[] array = new byte[(int) chosenFile.length()], firstArray = new byte[anySize], msgArray = new byte[msgByteSize];
		System.out.println(chosenFile.length());

		buffinput.read(firstArray, 0, firstArray.length);

		buffout.write(array);
		buffout.flush();

		// Nachricht vom Server lesen.
		buffMessage.read(msgArray);
		// Nachricht in String umwandeln
		String msg = new String(msgArray);
		System.out.println("Nachricht vom Server: " + msg);

		// Rest von der Datei einlesen
		buffinput.read(array, firstArray.length, array.length);

		buffout.write(array);
		buffout.flush();

		System.out.println("Gesendet");

		// Nachricht vom Server lesen.
		buffMessage.read(msgArray);
		// In String umwandeln
		msg = new String(msgArray);
		System.out.println("Nachricht vom Server 2: " + msg);

		// close all streams
		buffout.close();
		input.close();
		buffinput.close();
		sock.close();
		timeEnd = System.currentTimeMillis();
		System.out.println("Time start: " + timeStart);
		System.out.println("Time end: " + timeEnd);
		System.out.println("Difference: " + (timeEnd - timeStart));
		System.out.println("Time taken in seconds: " + (timeEnd - timeStart)
				/ 1000);
		System.exit(0);
	}
}
```

Ich habe den Code von KingOfExceptions mir einmal vorgenommen (nur den Client, da der Server schon existiert) und diesen erweitert, sodass er deinen Ansprüchen gerecht werden sollte. Habe ihn selbst noch nicht getestet! Ich vermute auch, dass die Antwort vom Server ein String ist, weshalb ich die Klasse um einen BufferedReader erweitert habe. Mit BufferedInputStream kann man nur Bytes auslesen.

[EDIT]Nochmal den Code etwas überarbeitet, nachdem ich gelesen habe, dass der Server keine Strings, sondern Zahlenbytes schickt. Habe das jetzt mal mit einem weiteren Byte-Array und einer frei bestimmbaren Größe erweitert und angepasst. Jetzt sollte es den vollständigen Ansprüchen des TOs entsprechen.

Der Server von KingOfException müsste dementsprechend auch überarbeitet werden, wenn man die überarbeitete Klasse (UploaderFile) mit dem Server verwenden möchte![/EDIT]


----------



## Computerbabalul (5. Jul 2012)

Hallo zusammen

Danke für eure Mühe, ich habe es nun hin bekommen!

Falls es jemanden noch interessiert hier der Code zum senden:


```
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;


public class FileProvider implements Runnable {

    final String ahost;
    final String afilename;
    final int aport;

    public FileProvider(String ahost, String afilename, int aport) {
        this.ahost = ahost;
        this.afilename = afilename;
        this.aport = aport;
    }

    @Override
    public void run() {
        try {
            Socket sock = new Socket(this.ahost, this.aport);
            long time = System.currentTimeMillis();
            DataInputStream dataInputStream = new DataInputStream(sock.getInputStream());
            OutputStream out = sock.getOutputStream();
            FileInputStream fileInputStream = new FileInputStream(this.afilename);

            byte[] buffer = new byte[128 * 1024];
            int bytesRead = 0;
            long totalSent = 0;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                if (bytesRead > 0) {
                    out.write(buffer, 0, bytesRead);
                    totalSent += bytesRead;
                    System.out.println("sent " + totalSent);
                }
            }
            int length;
            byte[] abuffer = new byte[4];
            while ((length = dataInputStream.read(abuffer)) != -1) {
                for (int i = 0; i != length; i++) {
                    System.out.println(abuffer[i]);
                }
                System.out.println();
            }
            sock.close();
            System.out.println("Sent " + java.lang.Math.round((totalSent / 1024.0 / 1024.0)) + " MB in "
                    + java.lang.Math.round((System.currentTimeMillis() - time) / 1000.0) + "sec.");
        } catch (UnknownHostException ex) {
            Logger.getLogger(FileProvider.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FileProvider.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
```

Die erste Servernachricht lasse ich hier allerdings weg, mich interessiert nur
die letzte, diese besagt ob der Datei fehlerfrei importiert wurde.

Gruß Baba


----------

