socket()/ read()上的Socket InputStream块

时间:2013-12-12 19:15:54

标签: java sockets blocking

我正在阅读Socket InputStream,调用read()和available()适用于少量循环迭代。以后可用()无限期地阻止!

可能是什么问题?我怎样才能使这种非阻塞?

代码:

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);
    }
}

3 个答案:

答案 0 :(得分:4)

available()对于套接字不是一个好主意,因为它不能按预期工作。我会在这个地方使用非阻塞NIO。

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();
}

这比IO版本效率更高,因为它不会将数据复制到Java scape中,只是为了将其复制回来(它可以保存两个副本)

编辑循环的规范版本如下:

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

答案 1 :(得分:3)

它没有阻止它旋转。

一旦没有可用数据,您的代码也可以阅读

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

循环永远不会完成。当没有可用数据时,将永远不会执行对减1值的测试。

你在堆栈跟踪中看到了available(),因为这是你的循环中唯一占用任何时间的东西,所以当你创建堆栈跟踪时,可能就是它将会是它的位置。

如果您确信您将获得文件结束条件(例如,如果它是TCP而另一端关闭连接),则根本不需要可用()调用。否则,您需要一种不同的方法来确定您拥有所有数据。例如,有效负载大小是在前几个字节中编码的还是什么?

答案 2 :(得分:1)

你的代码有一个很大的错误;你从未对available结果做过任何事情;所以你的read阻止。

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);
}