Just some guy
Just some guy

Reputation: 1959

Java - Files get corrupted when sent over socket, except when sent to localhost

I'm trying to build a file server and file client program in Java using sockets, and I've been running into some issues when trying to send files from the server to the client. Below is the code that I use to send and receive files respectively:

private void sendFile(String filePath) {
    try (BufferedInputStream fileInputStream = new BufferedInputStream(new FileInputStream(filePath))) {
        BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream());
        byte[] buffer = new byte[4096];
        while (fileInputStream.read(buffer) != -1) {
            outputStream.write(buffer);
            outputStream.flush();
        }
    }
    catch (IOException e) {e.printStackTrace();}
}

private void downloadFile(String fileName, long fileSize) {
    try (BufferedOutputStream fileOutputStream = new BufferedOutputStream(new FileOutputStream(downloadDir + "/" + fileName));
        BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
        OutputStreamWriter writer = new OutputStreamWriter(new BufferedOutputStream(socket.getOutputStream()), "UTF-8");) {
        writer.write("GET" + fileName + System.lineSeparator());
        writer.flush();
        long totalReceived = 0;
        int bufferSize = 4096;
        byte[] buffer = new byte[bufferSize];
        while (totalReceived < fileSize) {
            inputStream.read(buffer);
            int numOfBytesToWrite = fileSize - totalReceived > bufferSize ? buffer.length : (int)(fileSize % bufferSize);
            fileOutputStream.write(buffer, 0, numOfBytesToWrite);
            fileOutputStream.flush();
            totalReceived += numOfBytesToWrite;
        }
    }
    catch (IOException e) {}
}

The downloaded file does get created and seems to be of the right size, but always gets corrupted and cannot be opened by any program. However, this issue does not show itself when I run the client on the same machine and connect it to "localhost" or "127.0.0.1", then there are no problems and downloaded files are not corrupted. See any issues with my code?

Upvotes: 3

Views: 967

Answers (1)

Adam
Adam

Reputation: 36703

In your sendFile() you need to consider the return value from the read() which may be less than 4096... This value should then be used in the write call to only write out the portion of the array that has been populated...

int bytesRead = 0;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
    outputStream.write(buffer, 0, bytesRead);
    outputStream.flush();
}

A similar problem occurs in downloadFile(), return from read() is the actual number of bytes read, some value less than or equal to 4096...

long totalReceived = 0;
int bufferSize = 4096;
byte[] buffer = new byte[bufferSize];
while (totalReceived < fileSize) {
    int bytesRead = inputStream.read(buffer);
    fileOutputStream.write(buffer, 0, bytesRead);
    fileOutputStream.flush();
    totalReceived += bytesRead;
}

Why does your code work on localhost, but not over a network?

  • Atypical physical layer of a network is Ethernet, this will have a MTU of 1500 bytes. So you'll probably be seeing successive read() calls only filling 1500, or fewer bytes of your buffer...

  • However, localhost is optimized in the stack to bypass the physical layer which will not have this limitation. It is likely in this case successive calls will fill the full 4096 buffer, apart from the last, unless your file size is exact multiple of 4096.

Upvotes: 4

Related Questions