Exactly what read/block guarantees does DataInputStream provide following available()

379 Views Asked by At

I've read the java docs and a number of related questions but am unsure if the following is guaranteed to work:

I have a DataInputStream on a dedicated thread that continually reads small amounts of data, of known byte-size, from a very active connection. I'd like to alert the user when the stream becomes inactive (i.e. network goes down) so I've implemented the following:

...
streamState = waitOnStreamForState(stream, 4);
int i = stream.readInt();
...

private static int
waitOnStreamForState(DataInputStream stream, int nBytes) throws IOException {
    return waitOnStream(stream, nBytes, STREAM_ACTIVITY_THRESHOLD, STREAM_POLL_INTERVAL)
            ? STREAM_STATE_ACTIVE 
            : STREAM_STATE_INACTIVE;

private static boolean
waitOnStream(DataInputStream stream, int nBytes, long timeout, long pollInterval) throws IOException {
    int timeWaitingForAvailable = 0;
    while( stream.available() < nBytes ){
        if( timeWaitingForAvailable >= timeout && timeout > 0 ){
            return false;
        }
        try{
            Thread.sleep(pollInterval);
        }catch( InterruptedException e ){
            Thread.currentThread().interrupt();
            return (stream.available() >= nBytes);
        }
        timeWaitingForAvailable += pollInterval;
    }
    return true;
}

The docs for available() explain:

Returns an estimate of the number of bytes that can be read (or skipped over) from this input stream without blocking by the next caller of a method for this input stream. The next caller might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.

Does this mean it's possible the next read (inside readInt()) might only, for instance, read 2 bytes, and the subsequent read to finish retrieving the Integer could block? I realize readInt() is a method of the stream 'called next' but I presume it has to loop on a read call until it gets 4 bytes and the docs don't mention subsequent calls. In the above example is it possible that the readInt() call could still block even if waitOnStreamForState(stream, 4) returns STREAM_STATE_ACTIVE?

(and yes, I realize my timeout mechanism is not exact)

1

There are 1 best solutions below

6
On BEST ANSWER

Does this mean it's possible the next read (inside readInt()) might only, for instance, read 2 bytes, and the subsequent read to finish retrieving the Integer could block?

That's what it says. However at least the next read() won't block.

I realize readInt() is a method of the stream 'called next' but I presume it has to loop on a read call until it gets 4 bytes and the docs don't mention subsequent calls. In the above example is it possible that the readInt() call could still block even if waitOnStreamForState(stream, 4) returns STREAM_STATE_ACTIVE?

That's what it says.

For example, consider SSL. You can tell that there is data available, but you can't tell how much without actually decrpyting it, so a JSSE implementation is free to:

  • always return 0 from available() (this is what it used to do)
  • always return 1 if the underlying socket's input stream has available() > 0, otherwise zero
  • return the underlying socket input stream's available() value and rely on this wording to get it out of trouble if the actual plaintext data is less. (However the correct value might still be zero, if the cipher data consisted entirely of handshake messages or alerts.)

However you don't need any of this. All you need is a read timeout, set via Socket.setSoTimeout(), and a catch for SocketTimeoutException. There are few if any correct uses of available(): fewer and fewer as time goes on, it seems to me. You should certainly not waste time calling sleep().