【问题标题】:Files shared through java socket programming end up being corrupt at the receiving end通过 java 套接字编程共享的文件最终在接收端损坏
【发布时间】:2016-12-28 11:43:31
【问题描述】:

我正在尝试创建一个允许服务器和客户端相互发送文件的客户端/服务器程序。我创建了套接字,并将客户端连接到服务器。我现在正在同一台计算机上做这个。如果完善了,我会拿到另一台电脑上试试。

我的问题是文件传输成功但已损坏。收到的文件已损坏,但原件没问题。我遇到了套接字异常的问题,其中套接字在发送文件后不断重置,但我已经设法解决了这个问题。现在文件已发送,但尚未完成。

接收到的文件大小小于发送的文件大小,导致接收到的文件不工作。我通过网络发送了一个 pdf 文件。原来是695kb左右,但收到的文件是688kb,导致文件损坏。我也尝试发送视频,并得到相同的结果。收到的文件比发送的文件小。

我检查了程序,但看不出问题出在哪里。 我尝试实现的发送方法是零复制方法,其中文件中的数据直接发送到套接字,从套接字直接读取到文件。在将其发送到输出流之前,我没有使用将其存储在缓冲区中的其他方法。这是因为我希望能够使用该程序发送大文件。大文件会填满java堆内存,而且这种方法速度更快。

缓冲方法:

....
File file = new File("path to file);
BufferedInputStream = new BufferedInputStream(new FileInputStream(file));
BufferedOutputStream out = new      BufferedOutputStream(socket.getOutputStream());

byte[] buf = new byte[length];
in.read(buf, 0, buf.length);
out.write(buf, 0, buf.length);
....

我没有使用这种缓冲方法。这是我的代码。这是文件服务器

import java.io.*;
import java.net.*;

import javax.swing.JFileChooser;

public class ShareServer {

    public static void main(String args[]) {
        int port = 4991;
        ServerSocket server;
        Socket socket = null;
        BufferedInputStream in = null;
        BufferedOutputStream out = null;

        try {
            server = new ServerSocket(port);
            System.out.println("Waiting for connection request..");

            socket = server.accept();

            System.out.println("Connected to " + socket.getInetAddress().getHostName());

            JFileChooser fc = new JFileChooser();
            File file = null;

            if (fc.showOpenDialog(null) == JFileChooser.APPROVE_OPTION)
                file = fc.getSelectedFile();

            // send out the reference of the file using writeObject() method
            new ObjectOutputStream(socket.getOutputStream()).writeObject(file);

            in = new BufferedInputStream(new FileInputStream(file));
            out = new BufferedOutputStream(socket.getOutputStream());

            // send file
            int b = 1;
            while (b != -1){
                b = in.read();
                out.write(b);
            }

            System.out.println(file.getName() + " has been sent successfully!");

        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }

        try {
            in.close();
            out.close();
            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这是客户端类:

import java.io.*;
import java.net.*;

import javax.swing.JOptionPane;

public class ShareClient {
    public ShareClient() {

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        String host = InetAddress.getLocalHost().getHostAddress();

        Socket socket = new Socket(host, 4991);
        System.out.println("Connected to " + host);

        // receive the file object. this does not contain the file data
        File refFile = (File) new ObjectInputStream(socket.getInputStream()).readObject();

        System.out.println("File to receive " + refFile.getName());

        // create a new file based on the refFile
        File newFile = new File(System.getProperty("user.home") + "/desktop/ReceivedFiles", refFile.getName());

        BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
        BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(newFile));

        System.out.println("Receiving file now...");

        int b;
        while ((b = in.read()) != -1)
            out.write(b);

        System.out.println("File has been received successfully!");

        socket.close();

    }

}

服务器和客户端类运行成功,没有任何异常,文件已发送,但已损坏。它是不完整的。 请注意,通过 ObjectInput 和 ObjectOutput 流发送的文件不是真正的文件,而只是一个文件对象,其中包含我要发送的文件的所有信息,而不是文件的二进制数据。

请问有人可以帮助我吗?为什么文件损坏或不完整?它被读取到最后(当 -1 时)返回,并且所有字节都被发送,但由于某种原因我无法解释,它最终小于原始文件的大小。

【问题讨论】:

    标签: java sockets network-programming


    【解决方案1】:

    目前,您在文件末尾写入-1(此时您应该停止)。类似的,

    int b = 1;
    while (b != -1){
        b = in.read();
        if (b != -1) {
            out.write(b);
        }
    }
    

    int b;
    while ((b = in.read()) != -1) {
        out.write(b);
    }
    

    【讨论】:

      【解决方案2】:

      我终于找到了问题的答案!事情就是这么简单!缓冲区。我只是添加了一小行代码来刷新服务器中的套接字输出流缓冲区,并刷新客户端程序中的文件输出流缓冲区,就是这样!似乎一些字节的数据留在了缓冲区中,这使得文件不完整。这是缓冲输入和输出的问题之一。如果您忘记刷新缓冲区,就会开始遇到问题。

      代码如下:

      int b = 1;
      while(b != -1){
          out.write(b);
      }
      out.flush(); //this solved my problem. I also did it in the client class
      

      非常感谢您的回答@Elliot Frisch :)

      【讨论】:

        猜你喜欢
        • 2014-08-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-08
        • 1970-01-01
        • 2016-12-08
        • 1970-01-01
        相关资源
        最近更新 更多