问题
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);
}
}
回答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?
回答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();
}
回答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);
}
来源:https://stackoverflow.com/questions/20552223/socket-inputstream-blocks-on-available-read