Karl Jamoralin
Karl Jamoralin

Reputation: 1260

Missing bytes in sending files over TCP connection

Some bytes are missing when I'm sending files over TCP connection. Though there are times that file transfer is complete.

Sending side:

class SendFile extends Thread {

Socket s;
String toIP;
String fileName;
PrintWriter pw;
BufferedReader br;
String fromIP;
String nextHopIP;
String transferTime;
int routingIndex;
final int bufferSize = 65536;
int readFile;
byte[] buffer;
FileInputStream fileIn;
OutputStream fileOut;
long fileTransferTime;

SendFile(String toIP, String fileName) {
    this.toIP = toIP;
    this.fileName = fileName;
}

public void run() {
    while (true) {
        try {
            fromIP = InetAddress.getLocalHost().getHostAddress();
            nextHopIP = Tables.checkRoutingTable(toIP);

            if (nextHopIP.equals("none")) {
                System.out.println("Invalid IP address");
            } else {
                s = new Socket(nextHopIP, 3434);

                fileIn = new FileInputStream(fileName);
                fileOut = s.getOutputStream();
                buffer = new byte[bufferSize];
                pw = new PrintWriter(s.getOutputStream());
                br = new BufferedReader(new InputStreamReader(s.getInputStream()));

                pw.println(fromIP);
                pw.println(toIP);
                pw.println(fileName.split("\\\\")[fileName.split("\\\\").length - 1]);
                pw.flush();

                //Send file
                fileTransferTime = System.currentTimeMillis();
                int sum = 0;
                while ((readFile = fileIn.read(buffer)) != -1) {
                    fileOut.write(buffer, 0, readFile);
                    sum += readFile;
                }
                System.out.println(sum);
                fileIn.close();
                s.shutdownOutput();
                br.readLine();
                fileTransferTime = System.currentTimeMillis() - fileTransferTime;
                System.out.println("File transfer time: " + fileTransferTime + " ms");
                s.close();
                break;
            }

        } catch (IOException ex) {
            //Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("Connection timed out. Retrying...");
        }
    }
}

}

Receiving side:

class FileTransferThread extends Thread {

Socket fromSocket;
Socket toSocket;
String ip;
BufferedReader fromBR;
BufferedReader toBR;
PrintWriter fromPW;
PrintWriter toPW;
String[][] delta;
String token;
String toIP;
String fromIP;
String nextHopIP;
String absoluteFileName;
String fileName;
int deltaCount;
int entryCount;
int socketIndex;
int i;
int j;
int readFile;
final int bufferSize = 65536;
byte[] buffer;
InputStream fileIn;
FileOutputStream fileOut;
OutputStream fileHopOut;
File directory;
long fileTransferTime;

FileTransferThread(Socket s) {
    this.fromSocket = s;
}

public void run() {
    try {
        ip = InetAddress.getLocalHost().getHostAddress();
        fromBR = new BufferedReader(new InputStreamReader(fromSocket.getInputStream()));
        fromPW = new PrintWriter(fromSocket.getOutputStream());
        fromIP = fromBR.readLine();
        toIP = fromBR.readLine();
        nextHopIP = Tables.checkRoutingTable(toIP);
        buffer = new byte[bufferSize];
        fileIn = fromSocket.getInputStream();
        fileName = fromBR.readLine();

        if (!fileName.equals("\\send")) {
            directory = new File("c:\\" + fromIP);
            directory.mkdirs();
            absoluteFileName = "c:\\" + fromIP + "\\" + fileName;
            fileOut = new FileOutputStream(absoluteFileName);

            while (true) {
                try {
                    //if not yet the destination IP, pass to next hop
                    if (!toIP.equals(ip)) {
                        toSocket = new Socket(toIP, 3434);
                        fileHopOut = toSocket.getOutputStream();
                        toBR = new BufferedReader(new InputStreamReader(toSocket.getInputStream()));
                        toPW = new PrintWriter(toSocket.getOutputStream());
                        toPW.println(fromIP);
                        toPW.println(toIP);
                        toPW.println(fileName);
                        toPW.flush();

                        //Send file
                        while ((readFile = fileIn.read(buffer)) != -1) {
                            fileHopOut.write(buffer, 0, readFile);
                        }
                        toSocket.shutdownOutput();
                        fromPW.println(toBR.readLine());
                        fromPW.flush();
                        toSocket.close();
                    } else {
                        int sum = 0;
                        while ((readFile = fileIn.read(buffer)) != -1) {
                            fileOut.write(buffer, 0, readFile);
                            sum += readFile;
                        }
                        System.out.println(sum);
                        fileOut.flush();
                        fileOut.close();
                        fromPW.println("1");
                        fromPW.flush();
                    }
                    fromSocket.close();
                    break;
                } catch (IOException ex) {
                    //Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
                    System.out.println("Connection timed out. Retrying...");
                }
            }
        } else {
            while(true) {
                try {
                    //if not yet the destination IP, pass to next hop
                    if (!toIP.equals(ip)) {
                        toSocket = new Socket(toIP, 3434);
                        fileHopOut = toSocket.getOutputStream();
                        toBR = new BufferedReader(new InputStreamReader(toSocket.getInputStream()));
                        toPW = new PrintWriter(toSocket.getOutputStream());
                        toPW.println(fromIP);
                        toPW.println(toIP);
                        toPW.println(fileName);
                        toPW.flush();
                        //Send file
                        while ((readFile = fileIn.read(buffer)) != -1) {
                            fileHopOut.write(buffer, 0, readFile);
                        }
                        toSocket.shutdownOutput();
                        fromPW.println(toBR.readLine());
                        fromPW.flush();
                        toSocket.close();
                    } else {
                        while ((readFile = fileIn.read(buffer)) != -1) {
                        }
                        fromPW.println("1");
                        fromPW.flush();
                    }
                    fromSocket.close();
                    break;
                }
                catch (IOException ex) {
                    //Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
                    System.out.println("Connection timed out. Retrying...");
                }
            }
        }
        fromSocket.close();
    } catch (IOException ex) {
        Logger.getLogger(FileTransferThread.class.getName()).log(Level.SEVERE, null, ex);
    }

}

}

Upvotes: 2

Views: 2498

Answers (3)

Karl Jamoralin
Karl Jamoralin

Reputation: 1260

Found the error. It seems that BufferedReader is getting a chunk of data which is supposed to be for the file.

Upvotes: 0

meriton
meriton

Reputation: 70564

You are not closing - and hence not flushing - the SocketOutputStream called fileout. (You really should consider less misleading names ...).

Hm ... it appears shutdownOutput does that; its javadoc writes:

Disables the output stream for this socket. For a TCP socket, any previously written data will be sent followed by TCP's normal connection termination sequence.

If you write to a socket output stream after invoking shutdownOutput() on the socket, the stream will throw an IOException.

I leave this in case anybody else has the same idea.

Upvotes: 1

msw
msw

Reputation: 43487

Note that socket.getInputStream specifies the sorts of data loss that can happen using that facility. In particular:

The network software may discard bytes that are buffered by the socket.

Upvotes: 0

Related Questions