tags:

views:

133

answers:

3

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);
    }

}

}

A: 

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.

msw
I think that applies to buffered streams. Would that also be applicable to OutputStream? I'm under the impression that OutputStream does not buffer data, thus the absence of a flush statement in my code. Though I tried adding a flush statement after the loop but still there are still bytes missing.
xnikolai
+1  A: 

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.

meriton
fileOut in the receiving side is an OutputStream object. From javadocs: The flush method of OutputStream does nothing.
xnikolai
A: 

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

xnikolai