How can you force a flush on an OutputStream object without closing it?
Asked Answered
P

7

6

My question lies on the following assumptions which I hope are true, because I believe these as I read them while Googling my problems:

  1. Closing a Socket's OutputStream closes the socket too
  2. The flush() method of OutputStream does nothing

So I basically need to anyhow flush the data out of my OutputStream object for my app to work.

If you're interested in details then please see the following two links :

. Weird behavior : sending image from Android phone to Java server (code working)

This issue was resolved by closing the OutputStream. Doing that flushed all the data to the other end of the socket and made my app working further but this fix soon gave rise to problem number 2 - the corresponding socket also gets closed :

. SocketException - 'Socket is closed' even when isConnected() returns true

Profitsharing answered 15/4, 2012 at 22:27 Comment(0)
R
6

You can call the flush method of OutputStream instead of close. The concrete classes inheriting from OutputStream will override flush() to do something other than nothing (writing the data to a file or sending it over the network).

Rumba answered 15/4, 2012 at 22:31 Comment(2)
But if you see the first question that I posted, the image transferred over the socket doesn't get transferred till the OutputStream is closed. And using flush() doesn't help there. What do you suggest there then?Profitsharing
In the link you have posted the server is waiting for an EOF (end of file) on the stream. An EOF is signalled by closing the stream and the TCP connection - so the server is running in the loop until you close the output stream on the client side. If you do not wish to close the stream after transferring the image you have to devise another method for signalling when the image transfer is complete. The simplest way to do that is to send the image size in as an integer (4 bytes) before sending the image. Then the server can read up to that amount of bytes before quitting the loop.Rumba
F
4

The flush() method of OutputStream does nothing.

This is incorrect.

It is true that the base implementation of flush() provided by the OutputStream class does nothing. However, your app will be calling the version of that method that is provided by actual stream class that you are using. If the stream class doesn't have direct write semantics, it will override flush() to do what is required.

In short, if a flush is required (and it is required for a Socket output stream), then calling flush() will do the right thing. (If some internet source tells you otherwise it is either wrong or you are misinterpreting it.)


FYI, the reason that the base OutputStream implements flush() as a no-op is that:

  • some output stream classes don't need to do anything when flushed; e.g ByteArrayOutputStream, and
  • for the stream classes where flush() is not a no-op, there is no way to implement the operation at the base class level.

They could (in theory) have made designed the stream APIs so that OutputStream was an abstract class (and flush() an abstract method) or an interface. However this API was effectively frozen prior to Java 1.0, and at that time there wasn't enough experience with practical Java programming to realize that the API design was suboptimal.

Fallen answered 16/4, 2012 at 0:13 Comment(0)
U
1

Closing a Socket's OutputStream closes the socket too

True.

The flush() method of OutputStream does nothing

False. There are overrides. See the Javadoc for FilterOutputStream.flush(), BufferedOutputStream.flush(), ObjectOutputStream.flush(), to name a few. All the streams that can buffer output internally have flush() methods. All the streams that don't, don't. Specifically, the output stream resulting from Socket.getOutputStream() is not buffered and does not override flush().

So your initial problem is non-existent, so you have no need for the 'solution' that causes problem #2.

Ursi answered 15/4, 2012 at 22:30 Comment(2)
But then what do you propose for problem#1? Initially I did use flush() instead of close() over the OutputStream but the image wouldn't get transferred then..Profitsharing
The solution for problem #1 is not to close the stream. If the peer needs end of stream to know when a message is complete, you're using an application protocol that will only allow one message, so you need to change it. There are no messages in TCP, only a byte stream. Messages are up to you.Ursi
A
0

Do you really need to flush? I also had an issue, where listener on c# server couldn't receive data sent from android (I tried to get the data synchronously).

I was sure that this is because on Android side, the following code didn't flush.

OutputStream str = btSocket.getOutputStream();
str.write(data_byte);
// "This implementation does nothing"
str.flush();

It turned out, that if I use asynchronous data retrieval on server's listener - it gets the data, and no flush() on client's side is required!

Accent answered 19/4, 2013 at 9:19 Comment(1)
Correct. Writing to a socket output stream isn't buffered by Java so no flush() is required. It is only required on streams that buffer, and they all have flush() overrides.Ursi
R
-1

I'll take a stab at it. I was having the same problem. closing the outputstream is the only way i can "flush" the data. but since i still need the outputstream that's not an option. so 1st i send the byte array length, out.writeInt, then the array itself. when all bytes have been read ie buffer.length == in.readInt() i break loop

    ByteArrayOutputStream dataBuffer = new ByteArrayOutputStream();
    byte[] buffer = new byte[1024];
    byte[] fileBytes;
    int n;
    int length;

    try
    {
        size = in.readInt();

        while((n = in.read(buffer)) != -1)
        {
            dataBuffer.write(buffer, 0, n);

            if(dataBuffer.toByteArray().length == length)
            {
                fileBytes = dataBuffer.toByteArray(); break;
            }
        }
    }
Rebuild answered 24/8, 2013 at 17:28 Comment(1)
"closing the outputstream is the only way i can "flush" the data. ": false. If the stream doesn't have a flush() override it's because it doesn't buffer anything. Otherwise it does buffer and it has a flush() override.Ursi
M
-1

I had the same problem. Add "\n" at the end of the stream. flush works but the destinary does not know if the message ended

Moyra answered 29/1, 2014 at 9:4 Comment(1)
If you're sending lines. If you're sending something else this won't work. More probably you were using readLine() at the receiver and not sending line terminators at the sender, which isn't a flushing problem at all, it is an application protocol problem. All the data would have arrived but the receiver would still be blocking forever waiting for the missing line terminator.Ursi
L
-1

YES on Android flush() do nothing (example based on api 23)

public Socket() {
    this.impl = factory != null ? factory.createSocketImpl() : new PlainSocketImpl();
    this.proxy = null;
}

public class PlainSocketImpl extends SocketImpl {

    @Override protected synchronized OutputStream getOutputStream() throws IOException {
        checkNotClosed();
        return new PlainSocketOutputStream(this);
    }


}

private static class PlainSocketOutputStream extends OutputStream {
        // doesn't override base class flush();
}

to flush output stream without closing socket you can shutdown output:

protected void shutdownOutput() throws IOException

-- this will close WRITE file descriptor.

instead of using output stream you can write directly to file descriptor or by creating own Socket implementation with OutputStream which will override flush method (for example using a Berkeley socket implementation in c (via native call).

It doesn't need to do anything. Writing to a socket output stream directly isn't buffered by Java, so there is nothing to flush. -user207421

  • we talking here about dalvik/art jvm implementation
  • tho op wanted confirmation on 2 questions & both were answered here
Look answered 20/6, 2016 at 20:36 Comment(1)
It doesn't need to do anything. Writing to a socket output stream directly isn't buffered by Java, so there is nothing to flush.Ursi

© 2022 - 2024 — McMap. All rights reserved.