【问题标题】:Why doesn't DataInputStream continue to receive data after reading binary file为什么DataInputStream读取二进制文件后不继续接收数据
【发布时间】:2023-04-06 06:10:01
【问题描述】:

我正在创建一个服务器来接收来自客户端的文本和二进制数据。它适用于文本数据以及第一次接收二进制文件,但此后它没有继续读取数据并引发异常。 这是我的服务器代码:

public class ConnectedProcessThread implements Runnable{
    private final Socket socket;

    public ConnectedProcessThread(Socket clientSocket){
        socket = clientSocket;
    }

    public void run(){
        DataInputStream dis = null;
        try{
            while(true) {
                dis = new DataInputStream(socket.getInputStream());
                String meta = dis.readUTF();
                Log.i("Data received", meta);
                if(meta.equalsIgnoreCase("Text")){
                    String message = dis.readUTF();
                    Log.i("Data received", message);
                }else if(meta.equalsIgnoreCase("Binary")){
                    InputStream is = socket.getInputStream();
                    ByteArrayOutputStream stream = new ByteArrayOutputStream();
                    byte[] buf = new byte[4096];
                    int len;
                    while((len=is.read(buf))>-1){
                        stream.write(buf,0,len);
                    }
                    stream.flush();

                    //read object input
                    try {
                        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
                        byte[] buffer = (byte[])ois.readObject();
                        FileOutputStream fos = new FileOutputStream("/storage/emulated/0/DCIM/IMG-Saved.jpeg");
                        fos.write(buffer);
                    }catch (ClassNotFoundException e){
                        e.printStackTrace();
                    }
                    finally {
                        Log.i("Binary_Transfer","File created");
                    }
                }
            }
        } catch (IOException e){
            e.printStackTrace();
        }finally {
            Log.i("Client_Socket","Stream will close");
            if(dis!=null){
                try {
                    dis.close();
                }catch (IOException e){
                    e.printStackTrace();
                }
            }
        }
    }
}

对于文本和二进制数据,在发送数据之前,客户端会发送文本元数据来通知服务器数据是文本还是二进制。但是在接收到文件(图像)后,它会在以下行抛出 EOFException: String meta = dis.readUTF();我猜这是因为在读写二进制文件后,线程继续循环,因此 DataInputStream 将再次读取,现在没有任何内容可接收,所以 readUTF() 抛出 EOFException。我尝试在发送二进制文件后从客户端发送元数据,以让 DataInputStream 可以读取某些内容而不抛出异常,但它不起作用,客户端确实发送了元数据但服务器仍然抛出 EOFException。任何人都知道问题是什么?非常感谢。

这是我从客户端发送二进制文件的方法:

public void sendBinaryData(byte[] binaryData){
    if(dos!=null && socket!=null){
        try {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeObject(binaryData);
            Log.d("Binary_Transfer", "C: Sent.");
            oos.close();
            dos.writeUTF("Binary_End");
            dos.flush();
        }catch (Exception e){
            Log.e("File_Exception",e.toString());
        }
    }
}

【问题讨论】:

    标签: java bytearray binaryfiles objectinputstream datainputstream


    【解决方案1】:

    因为当您开始读取二进制数据时,您进入了一个仅在流结束时终止的循环,即当对等方断开连接时:

    while((len=is.read(buf))>-1){
        stream.write(buf,0,len);
    }
    

    此时您处于流的末尾。没有更多的数据,没有更多的数据,也永远不会有更多的数据。

    您需要完全删除这部分:

    InputStream is = socket.getInputStream();
    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    byte[] buf = new byte[4096];
    int len;
    while((len=is.read(buf))>-1){
        stream.write(buf,0,len);
    }
    stream.flush();
    

    无论如何,将内容读入ByteArrayOutputStreams 几乎没有任何意义,这也不例外。完全删除它,然后更改下一部分:

    ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(stream.toByteArray()));
    

    ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
    

    并照常继续。但是你还有另一个问题:

    oos.close();
    

    这会关闭套接字。所以下一部分:

    dos.writeUTF("Binary_End");
    dos.flush();
    

    不可能工作。只需刷新ObjectOutputStream 而不是关闭它。

    但我强烈建议您放弃DataInput/OutputStreams,并在两端使用单个ObjectInput/OutputStream

    【讨论】:

    • 一个关键点,当然,是OP应该使用readObject()来读取接收端的byte[]
    • @jtahlborn 阅读他的代码。这正是他已经在做的事情。他的问题是前面的垃圾,并关闭了ObjectOutputStream
    • 啊,在嵌套对象流中。由于某种原因,我昨晚也忽略了这一点。
    • @tjahlborn 谢谢。我将遵循这种方法。那么ObjectOutputStream可以用来发送文本数据吧?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-12
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多