简体   繁体   中英

Java - Wait for stream to finish writing?

I have a "server" running in java and I am sending files via byte array to a "client" (android system). The functionality works fine, but I've noticed when I try to send larger files (1MB+), it doesnt successfully write all the bytes before closing (Ex: tried sending 5mb, and it only sent 902 bytes). Is there a way to have the code wait for the stream to finish writing before closing the stream? Below is the code and the stack trace. Essentially the send message method is called when a file is attached and sent (in a class that handles the GUI). In this case, I wasnt trying to receive data from the client, just send data TO the client.

EDIT:I am aware that I only have the byte array set to 1MB right now. I had it at 5MB, and it was still only writing <1MB. Even at 1MB, it was still only writing 902 bytes.

EDIT2: I have posted some of the code on the CLIENT side that handles receiving the data.

public void sendMessage(File file) {
    if(mOut != null) {
        try {
            FileInputStream inStream = new FileInputStream(file);               
            byte[] message = new byte[1024 * 1024];
            inStream.read(message);
            mOut.write(message, 0, message.length);
            mOut.flush();
            inStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        } 
    }
}

public void run() { 
    super.run();
    running = true;
    try {
        System.out.println("S: Connecting...");
        ServerSocket serverSocket = new ServerSocket(SERVERPORT);
        Socket client = serverSocket.accept();
        linked = true;
        System.out.println("S: Receiving...");

        try {
            mOut =client.getOutputStream();
            InputStream in = client.getInputStream();
            while(running) {
                byte[] message = new byte[1024 * 1024];
                 in.read(message);
                if(message != null && messageListener != null) {
                    messageListener.messageReceived(message);
                }
            }
        } catch (Exception ex) {
            System.out.println("S:Error");
            ex.printStackTrace();
        } finally {
            client.close();
            System.out.println("S:Done");
        }
    } catch (Exception ex) {
        System.out.println("S: Error");
        ex.printStackTrace();
    }

}
---------------------------------------------------------------------------
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at Server.sendMessage(Server.java:34)
at ServerBoard$2.actionPerformed(ServerBoard.java:57)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at Server.run(Server.java:58)

Here is a code snippet for the client.

    public void run() {
    mRun = true;
    serverMessage = new byte[1024 * 1024];
    try {
        InetAddress serverAddr = InetAddress.getByName(SERVERIP);
        Log.e("TCP Client", "C:Connecting...");
        Socket socket = new Socket(serverAddr, SERVERPORT);
        try {
            in = socket.getInputStream();
            while(mRun) {
                 in.read(serverMessage);
                if(serverMessage != null && mMessageListener != null) {
                    mMessageListener.messageReceived(new String(serverMessage));
            }
                serverMessage = null;
            }

            Log.e("RESPONSE FROM SERVER","S:Received Message: '" + serverMessage + "'");

        } catch(Exception ex) {
            Log.e("TCP","S: Error", ex);
        } finally {
            socket.close();
        }
    } catch(Exception ex) {
        Log.e("TCP","C: Error", ex);
    }
}

First, JavaDoc of read :

Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer. This method blocks until input data is available, end of file is detected, or an exception is thrown.

As the source is a socket, it may returns less bytes than expected, even if the buffer is sized at 1 MByte, returning 902 KBytes is Ok. You have to loop until end of stream.

The following method read all bytes, than calls listeners:

byte[] message = new byte[0]; 
byte[] buffer  = new byte[4096];
int    len;
while(( len = is.read( buffer )) > -1 ) {
   byte[] tmp = new byte[message.length+len];
   System.arraycopy( message, 0, tmp, 0, message.length );
   System.arraycopy( buffer , 0, tmp, message.length, len );
   message = tmp;
}
messageListener.messageReceived( message );

As you can see, a lot of reallocations occurs: you have to redesign your protocol to send the size of the file first and allocate once the receive buffer.

You're setting the read buffer to null before finishing reading:

 in = socket.getInputStream();
 while(mRun) {
     in.read(serverMessage);
     if(serverMessage != null && mMessageListener != null) {
         mMessageListener.messageReceived(new String(serverMessage));
     }
     serverMessage = null;
}

this will cause a NullPointerException and your code will close the socket.

设置socket.setSendBufferSize(1024) (你用来发送的)也确保在接收时你读取了1024字节的块。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM