Java-通过套接字发送文件时文件会损坏,但发送到本地主机时除外

标签 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”时,这个问题并没有出现,那么就没有问题,下载的文件也没有损坏。看到我的代码有任何问题吗?

最佳答案

在您的 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;
}

为什么您的代码可以在本地主机上运行,​​但不能通过网络运行?

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

  • 然而,本地主机在堆栈中进行了优化,以绕过物理层,不会有此限制。在这种情况下,除非您的文件大小恰好是 4096 的倍数,否则连续调用很可能会填满整个 4096 缓冲区,除了最后一个。

关于Java-通过套接字发送文件时文件会损坏,但发送到本地主机时除外,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36754356/

相关文章:

java - Apache Nutch Hadoop 集成

java - 如何在选择菜单项后启用recyclerview OnItemClickListener?

c - 进程之间,通过msg共享一个socket。使用套接字 getpeername 结果是 0.0.0.0 没有任何错误

c# - StreamReader.ReadLine() 在与 POP3 一起使用时总是失败

java - Java中的方法与构造函数

java - oracle.jdbc.driver.OracleDriver ClassNotFoundException 异常

java - 接口(interface)、类和子类继承

Android Media Player 使用本地套接字失败,播放 VoiceChat 流数据的解决方法是什么?

php - 在 php 中读取常量 UDP 流

c - 没有keepalive的物理断开的tcp套接字的生命周期