简体   繁体   English

通过TCP连接发送文件时丢失字节

[英]Missing bytes in sending files over TCP connection

Some bytes are missing when I'm sending files over TCP connection. 通过TCP连接发送文件时缺少一些字节。 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);
    }

}

} }

You are not closing - and hence not flushing - the SocketOutputStream called fileout . 您没有关闭-因此也没有刷新-名为fileout (You really should consider less misleading names ...). (您确实应该考虑减少误导性的名称...)。

Hm ... it appears shutdownOutput does that; 嗯...看来shutdownOutput可以做到; its javadoc writes: 其javadoc写道:

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. 对于TCP套接字,将发送任何先前写入的数据,然后是TCP的正常连接终止序列。

If you write to a socket output stream after invoking shutdownOutput() on the socket, the stream will throw an IOException. 如果在套接字上调用shutdownOutput()后写入套接字输出流,则该流将抛出IOException。

I leave this in case anybody else has the same idea. 万一其他人有相同的想法,我就离开这个。

Note that socket.getInputStream specifies the sorts of data loss that can happen using that facility. 请注意, socket.getInputStream指定使用该工具可能发生的各种数据丢失。 In particular: 尤其是:

The network software may discard bytes that are buffered by the socket. 网络软件可能会丢弃套接字缓冲的字节。

Found the error. 发现错误。 It seems that BufferedReader is getting a chunk of data which is supposed to be for the file. 似乎BufferedReader正在获取应该用于文件的数据块。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM