freeguy
freeguy

Reputation: 11

Files shared through java socket programming end up being corrupt at the receiving end

I am trying to create a client/server program that allows a server and client to send files to each other. I created the sockets, and connected the client to the server. I am doing this one the same computer for now. if it is perfected, i will take it to another computer and try it.

My problem is that the file is transferred successfully but it is corrupt. the file received is corrupt, but the original is okay. I've had problems with socket exception where the socket keeps resetting after sending the file, but I've managed to solve that problem. Now the file is sent, but it is not complete.

The size of the file received is smaller than the size of the file sent, and this causes the received file not work. I sent a pdf file over the network. the original was about 695kb, but the received file was 688kb, and this caused the document to be corrupt. I also tried sending a video, and had the same result. the received file is smaller than the sent file.

I have checked the program, but I can't see where the problem is coming from. The sending method i try to implement is the zero-copy method, where the data from the file is sent directly to the socket, from where it is read directly to the file. i did not use the other method where it is stored in a buffer before it is sent to the output stream. This is because I want to be able to use the program to send large files. Large files will fill up the java heap memory, and besides this method is faster.

buffer method:

....
File file = new File("path to file);
BufferedInputStream = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream out = new      BufferedOutputStream(socket.getOutputStream());

byte[] buf = new byte[length];
in.read(buf, 0, buf.length);
out.write(buf, 0, buf.length);
....

I did not use this buffer method. Here is my code. This is the file server

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

import javax.swing.JFileChooser;

public class ShareServer {

    public static void main(String args[]) {
        int port = 4991;
        ServerSocket server;
        Socket socket = null;
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            server = new ServerSocket(port);
            System.out.println("Waiting for connection request..");

            socket = server.accept();

            System.out.println("Connected to " + socket.getInetAddress().getHostName());

            JFileChooser fc = new JFileChooser();
            File file = null;

            if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
                file = fc.getSelectedFile();

            // send out the reference of the file using writeObject() method
            new ObjectOutputStream(socket.getOutputStream()).writeObject(file);

            in = new BufferedInputStream(new FileInputStream(file));
            out = new BufferedOutputStream(socket.getOutputStream());

            // send file
            int b = 1;
            while (b != -1){
                b = in.read();
                out.write(b);
            }

            System.out.println(file.getName() + " has been sent successfully!");

        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        try {
            in.close();
            out.close();
            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Here is the Client class:

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

import javax.swing.JOptionPane;

public class ShareClient {
    public ShareClient() {

    }

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

        String host = InetAddress.getLocalHost().getHostAddress();

        Socket socket = new Socket(host, 4991);
        System.out.println("Connected to " + host);

        // receive the file object. this does not contain the file data
        File refFile = (File) new ObjectInputStream(socket.getInputStream()).readObject();

        System.out.println("File to receive " + refFile.getName());

        // create a new file based on the refFile
        File newFile = new File(System.getProperty("user.home") + "/desktop/ReceivedFiles", refFile.getName());

        BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile));

        System.out.println("Receiving file now...");

        int b;
        while ((b = in.read()) != -1)
            out.write(b);

        System.out.println("File has been received successfully!");

        socket.close();

    }

}

The server and the client classes run successfully without any exceptions, and the file is sent, but it is corrupt. it is incomplete. Take note that the file sent through the ObjectInput and ObjectOutput streams is not the real file, but just a file object that has all the information of the filie i want to send, but not the binary data of the file.

Please can anybody help me? Why is the file corrupt or incomplete? It is read to the end (when -1) is returned, and all the bytes are sent, but for some reason i can't explain, it ends up being less than the size of the original file.

Upvotes: 0

Views: 673

Answers (2)

freeguy
freeguy

Reputation: 11

I have finally got the answer to the problem! It was something so simple! the buffer. I just added a small line of code to flush the socket outputstream buffer in the server, and flush the fileoutputstream buffer in the client program, and that was it! It seems some bytes of data was left in the buffer and that was making the file to be incomplete. this is one of the problems of buffered input and output. if you forget to flush the buffer, you start running into problems.

here's the code:

int b = 1;
while(b != -1){
    out.write(b);
}
out.flush(); //this solved my problem. I also did it in the client class

Thank you so much for your answer @Elliot Frisch :)

Upvotes: 0

Elliott Frisch
Elliott Frisch

Reputation: 201409

Currently, you write -1 at the end of the file (that's when you should stop). Something like,

int b = 1;
while (b != -1){
    b = in.read();
    if (b != -1) {
        out.write(b);
    }
}

or

int b;
while ((b = in.read()) != -1) {
    out.write(b);
}

Upvotes: 1

Related Questions