【问题标题】:File corrupted while sending through socket通过套接字发送时文件损坏
【发布时间】:2020-08-24 03:49:22
【问题描述】:

我只是想从一个套接字发送一些文件,并且我能够在没有任何中断的情况下发送这些文件:无论大小文件是小还是大,它都没有关系,它就像一个魅力一样发送。

但在我的情况下出现的问题是我发送的文件已损坏,即它不像音频或视频那样播放。我已经通过this,但它没有帮助。

我使用的代码如下。

服务器端:

File file = new File(
                Environment.getExternalStorageDirectory(),
                "testingFile.mp4");
        byte[] mybytearray = new byte[4096];
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        }
        BufferedInputStream bis = new BufferedInputStream(fis);
        DataInputStream dis = new DataInputStream(bis);
        OutputStream os;
        DataOutputStream dos = null;
        try {
            os = socket.getOutputStream();
            dos = new DataOutputStream(os);
            dos.writeUTF(file.getName());
            dos.writeLong(mybytearray.length);
            int read;
            while ((read = dis.read(mybytearray)) != -1) {
                dos.write(mybytearray, 0, read);
            }
            socket.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (dos != null) {
                    dos.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

还有客户端:

File file = new File(
                    Environment.getExternalStorageDirectory(),
                    "TEST SUCCESS.mp4");
            InputStream in = null;
            int bufferSize;

            try {
                bufferSize = socket.getReceiveBufferSize();
                in = socket.getInputStream();
                DataInputStream clientData = new DataInputStream(in);
                String fileName = clientData.readUTF();
                System.out.println(fileName);
                OutputStream output = new FileOutputStream(
                        file);
                byte[] buffer = new byte[bufferSize];
                int read;
                while ((read = clientData.read(buffer)) != -1) {
                    output.write(buffer, 0, read);
                }
                output.flush();
                socket.close();

            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                if (in != null) {
                    in.close();
                }

            }

提前致谢。

【问题讨论】:

  • 您能否向我们展示一个显示损坏的小文件的结果?请向我们展示原始文件,然后是损坏的文件。对不起;我假设这些是文本文件,而不是 mp4。
  • @NomadMaker 我正在发送 mp4 文件而不是文本。请帮我解决这个问题
  • 您正在从一个Socket 发送到另一个。 ServerSocket 与此无关。
  • 由于某种原因,您使用dos.writeLong(mybytearray.length) 发送缓冲区大小,但您从未读取它,因此它会在所有数据之前进入文件。你不需要这个。删除并重新测试。
  • @MarquisofLorne 所以请给我一些代码建议,以便我可以解决这个问题

标签: java sockets file-sharing


【解决方案1】:

因此,在 cmets 中的对话之后,正如 @MarquisofLorne 告诉我删除我在服务器端代码中编写的行。即从服务器端代码中删除此行:

dos.writeLong(mybytearray.length);

或在客户端代码中编写以下代码:

long sizeOfFile = clientData.readLong();

它解决了问题。

【讨论】:

    【解决方案2】:

    服务器端

    您的代码发送缓冲区长度(4096),这是一个错误。

    它应该发送文件长度。

    File file = new File( ... );
    try {
        //dos.writeLong(mybytearray.length);
        dos.writeLong(file.length());
    
    }
    

    客户端

    服务器发送两个元数据

    • 文件名(F字节,utf-8编码)
    • 文件长度(8 字节)

    然后发送全部内容(N字节)

    但客户端代码忽略文件长度(8字节),只读取文件名和内容N字节

        in = socket.getInputStream();
        DataInputStream clientData = new DataInputStream(in);
    
        String fileName = clientData.readUTF(); // ok read F bytes
        
        // missing readLong(..) 8 bytes
        // long fileLen = clientData.readLong(); <= read file length before reading contents
        
        // read N bytes, but first 8 bytes are file length, which are written into file.
        int read;
        while ((read = clientData.read(buffer)) != -1) {
            output.write(buffer, 0, read);
        }
    

    不要依赖-1

    您的代码在while 循环中一直依赖-1

      while ((read = dis.read(mybytearray)) != -1) {
        dos.write(mybytearray, 0, read);
      }
    
      while ((read = clientData.read(buffer)) != -1) {
        output.write(buffer, 0, read);
      }
    
    

    -1 表示异常状态。

    因为服务器知道文件的确切大小并写出文件,所以客户端应该从流中读取确切的字节长度。

    如果服务器发送 1234 字节,当客户端从 clientData.read(..) 读取 -1 时,它无法从流中读取内容,而不是流的结尾。

    【讨论】:

    • 这是 Java,而不是 C。-1 并不“表示异常状态”:它表示流结束。请参阅 Javadoc。他不需要发送文件长度。他现在工作的代码证明了这一点。
    • NB (file.length) 无法编译。
    • file.length 到 file.length()
    • 很好,一个错字已更正,一个重大错误包括一半的答案未更正;而且由于您没有建议他实际上应该对文件长度做什么,因此这里根本没有任何价值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    相关资源
    最近更新 更多