【问题标题】:Socket InputStream blocks on available() / read()available() / read() 上的 Socket InputStream 块
【发布时间】:2013-12-12 19:15:54
【问题描述】:

我正在阅读 Socket InputStream,调用 read() 和 available() 适用于少数循环迭代。稍后 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);
    }
}

【问题讨论】:

  • 我建议你试试 NIO,this 的问题可能会有所帮助。
  • 谢谢。你是说除了蔚来别无他法吗?
  • 您确定是available() 阻塞了吗?我不认为它应该阻塞,但是我使用 Java IO API 已经有一段时间了,所以我可能弄错了。
  • 堆栈跟踪如下(建议available() 正在等待)-
     PlainSocketImpl.socketAvailable() line: not available [native method] SocksSocketImpl(PlainSocketImpl).available()行:472 SocketInputStream.available() 行:217 BufferedInputStream.available() 行:381 

标签: java sockets blocking


【解决方案1】:

available() 对于 Sockets 来说不是一个好主意,因为它不能按预期工作。我会在这个地方使用非阻塞 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();
}

【讨论】:

  • 彼得,我在正确版本的循环中进行了编辑。您可能想丢失您的版本。最后可能会丢失数据。你假设 write 写了一切。
  • @EJP 写入一直在循环中,直到没有更多数据或连接丢失。你循环会更好,因为它在读取时不会阻塞写入。
【解决方案2】:

它没有阻塞它正在旋转。

一旦没有可用的数据,您的代码不妨阅读

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

循环永远不会结束。当没有可用数据时,您的负 1 值测试将永远不会执行。

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

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

【讨论】:

    【解决方案3】:

    您的代码有一个很大的错误;你从来没有对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);
    }
    

    【讨论】:

    • 我认为这不对。如果没有要读取的数据,则只读块
    猜你喜欢
    • 2013-05-27
    • 2014-09-10
    • 2012-05-28
    • 1970-01-01
    • 2012-05-28
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多