Socket InputStream blocks on available() / read()

11,287

Solution 1

It is not blocking it is spinning.

Once there is no data available you code might as well read

while (true)
{
    if (buffIn.available() > 0) // ALWAYS false now we've run out of data
    {
       // unreachable
    }
}

The loop will never finish. Your test for the minus 1 value will never be executed when there is no data available.

You are seeing available() in the stack trace because that's about the only thing in your loop that's taking up any time, so the chances are, when you create you stack trace, that's where it's going to be.

If you are confident that you will infact get an end-of-file condition (eg if it's TCP and the other end closes the connection) then the available() call is not required at all. Otherwise, you need a different method of determining you have all of the data. For example is the payload size encoded in the first few bytes or something?

Solution 2

available() is not a good idea for Sockets as it doesn't work as expected. I would use non-blocking NIO in this place.

SocketChannel sc = ...
sc.configureBlocking(false);
ByteBuffer bb = ByteBuffer.allocateDirect(32*1024);
while(sc.read(bb) > 0) {
    bb.flip();
    while(bb.remaining() > 0 && sc.write(bb) >= 0);
    bb.clear();
}

This is quite a bit more efficient than the IO version as it doesn't copy the data into the Java scape just to copy it back out (it saves two copies)

EDIT The canonical version of the loop is follows:

while (in.read(bb) > 0 || bb.position() > 0)
{
    bb.flip();
    out.write(bb);
    bb.compact();
}

Solution 3

Your code has a pretty big bug; you never did anything with the available result; so your read blocks.

if (buffIn.available() > 0)
{
    int amt = (buffIn.available() > buffer.length) ? buffer.length : 
        buffIn.available();
    len = buffIn.read(buffer, 0, amt); // <-- see ternary above.
    if (len == -1)
    {
        break;
    }
    baos.write(buffer, 0, len);
}
Share:
11,287
Praveen
Author by

Praveen

Updated on June 04, 2022

Comments

  • Praveen
    Praveen almost 2 years

    I'm reading Socket InputStream, calling read() and available() works for few looping iterations. Later available() blocks indefinitely!

    What could be the issue? How can I make this non-blocking?

    Code:

    BufferedInputStream buffIn = new BufferedInputStream(in);
    while (true)
    {
        if (buffIn.available() > 0)
        {
            len = buffIn.read(buffer, 0, buffer.length);
            if (len == -1)
            {
                break;
            }
            baos.write(buffer, 0, len);
        }
    }