Java - 通过套接字发送文件时损坏,除非发送到localhost

时间:2016-04-20 20:19:28

标签: java sockets

我正在尝试使用套接字在Java中构建文件服务器和文件客户端程序,在尝试将文件从服务器发送到客户端时,我遇到了一些问题。下面是我用来分别发送和接收文件的代码:

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

下载的文件确实已创建并且似乎大小合适,但总是被损坏并且无法由任何程序打开。但是,当我在同一台机器上运行客户端并将其连接到“localhost”或“127.0.0.1”时,此问题不会显示,然后没有问题,下载的文件也没有损坏。查看我的代码的任何问题?

1 个答案:

答案 0 :(得分:4)

在你的sendFile()中,你需要考虑read()的返回值,该值可能小于4096 ......然后应该在write调用中使用该值,只写出数组的部分人口稠密...

int bytesRead = 0;
while ((bytesRead = fileInputStream.read(buffer)) != -1) {
    outputStream.write(buffer, 0, bytesRead);
    outputStream.flush();
}

在downloadFile()中出现类似的问题,从read()返回的是实际读取的字节数,某些值小于或等于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;
}

为什么您的代码可以在localhost上运行,但不能通过网络运行?

  • 网络的非典型物理层是以太网,其MTU为1500字节。所以你可能会看到连续的read()调用只填充1500或更少的缓冲区字节......

  • 但是,在堆栈中优化localhost以绕过不具有此限制的物理层。在这种情况下,除了文件大小是4096的完全倍数之外,连续调用可能会填充整个4096缓冲区,除非你的文件大小是4096的完全倍数。