Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

java

sockets

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?

like image 817
Just some guy Avatar asked Aug 23 '26 16:08

Just some guy


1 Answers

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.

like image 174
Adam Avatar answered Aug 25 '26 05:08

Adam