Wysyłanie pliku na serwer za pomocą socket

0

Witam!

Powiedzcie proszę gdzie jest błąd, plik przesyła się na serwer ale gubione gdzieś są bajty. Suma md5 jest różna poprzesłaiu pliku.

public void sendFile(Socket clientSock, File transferFile) throws IOException {
		try {
			fc.setFileName(transferFile.getName());
			fc.setFileSize(transferFile.length());
			fc.setIpHost(clientSock.getLocalAddress().toString());
			fc.setPath(transferFile.getPath());
			try {
				fc.setMd5sum(md5sum(transferFile));
				System.out.println(fc.getMd5sum());
			} catch (NoSuchAlgorithmException | IOException ex) {
				Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
			}
			final ObjectOutputStream out = new ObjectOutputStream(clientSock.getOutputStream());
			out.writeObject(fc);
			out.flush();
			din = new DataInputStream(clientSock.getInputStream());
		} catch (final IOException ex) {
			Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
		}

		System.out.println("czekam");
		final String remoteFileExist = din.readUTF();
		System.out.println(remoteFileExist);
		if (!remoteFileExist.equalsIgnoreCase("FileExist")) {
			System.out.println(remoteFileExist);

			dout = new DataOutputStream(clientSock.getOutputStream());
			try {

				System.out.println("Sending File: " + transferFile.getName());

				final FileInputStream fin = new FileInputStream(transferFile);

				final byte b[] = new byte[1024];

				int read;

//				System.out.println("Size: " + transferFile.length());

				while ((read = fin.read(b)) != -1) {
					dout.write(b, 0, read);
					dout.flush();
				}
				fin.close();
				dout.writeUTF("The file is already downloaded.");
				System.out.println("Send Complete");
				dout.flush();
			} catch (final Exception e) {
				e.printStackTrace();
				System.out.println("An error occured");
			}
		}
	}
}
public void reciveFile(Socket clientSock, File file) {
		try {
			final ObjectInputStream in = new ObjectInputStream(clientSock.getInputStream());
			try {
				fc = (FileClass) in.readObject();

				// TODO: To gdzieś jest jakiś problem z przekazywaniem md5sum -> od strony
				// klienta który posiada plik md5sum jest prawidłowa,
				// jednak po przesłąniu obiektu ona się zmiena ??? problem z esyłaniem danych na
				// obiekcie??
				// do sprawdzenia jak będzie czas jeszcze.
				System.out.println(fc.getFileName() + " " + fc.getPath());
			} catch (final ClassNotFoundException ex) {
				Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
			}
		} catch (final IOException ex) {
			Logger.getLogger(FileTransfer.class.getName()).log(Level.SEVERE, null, ex);
		}

		try {
			din = new DataInputStream(clientSock.getInputStream());
			dout = new DataOutputStream(clientSock.getOutputStream());
		} catch (final IOException e1) {
			System.err.println("WARN: " + e1.getMessage() + " " + e1.getClass().getName());
		}

			try {

					System.out.println("Receving file: " + fc.getFileName());
					System.out.println("File Size: " + (fc.getFileSize() / (1024 * 1024)) + " MB");

					final byte b[] = new byte[1024];
					System.out.println("Receving file..");

					try {
						fos = new FileOutputStream(new File(file.getPath()), true);
						long bytesRead;
						do {
							bytesRead = din.read(b, 0, b.length);
							fos.write(b, 0, b.length);
						} while (!(bytesRead < 1024));
						fos.close();
					} catch (final IOException e) {
						System.err.println("WARN: " + e.getMessage() + " " + e.getClass().getName());
					}

					System.out.println("Comleted. " + file.getPath());
				}
			} catch (NoSuchAlgorithmException | IOException e) {
				System.err.println("WARN: reciveFile " + e.getMessage());
			}
	
			System.out.println("Comleted. " + file.getPath());
		}

	}

1

Widzę tutaj dwie rzeczy:

  1. Przy zapisie pliku zawsze zapisujesz pełną tablicę:
do {
    bytesRead = din.read(b, 0, b.length);
    fos.write(b, 0, b.length);
} while (!(bytesRead < 1024));

Czyli przykładowo jeśli pętla wykona się dwa razy - raz przeczyta 1024 bajty, potem 1000, to i tak zapisujesz 2048 bajtów. Zmień:

fos.write(b, 0, b.length);

na

fos.write(b, 0, bytesRead);
  1. Tutaj inna sprawa - jak w ogóle czytasz przychodzący strumień bajtów. Sockety ze swojej natury nie gwarantują ci, że w strumieniu przychodzącym w jednym momencie pojawią się wszystkie wysłane bajty. Tzn. możliwy jest scenariusz, że:
  • z serwera wysyłasz 4096 bajtów.
  • do gniazda klienta trafia pierwsze 2048 bajtów
  • klient je odczytuje, pętla się kończy, klient przestaje czytać
  • do gniazda klienta trafia kolejne 2048 bajtów

Zazwyczaj taki problem rozwiązuje się poprzez dodanie odpowiedniego protokołu na poziomie tablicy bajtów. Pierwsze ileśtam bajtów odpowiada za typ i długość wiadomości, dzięki czemu klient wie ile musi jeszcze czytać. Do tego oczywiście trzeba dodać mechanizm timeout'u, żeby w razie problemów klient nie czekał w nieskończoność.

1 użytkowników online, w tym zalogowanych: 0, gości: 1