如何终止 BufferedInputStream .read() 调用

Posted

技术标签:

【中文标题】如何终止 BufferedInputStream .read() 调用【英文标题】:How to kill a BufferedInputStream .read() call 【发布时间】:2012-02-20 22:13:27 【问题描述】:

我正在编写一个程序来从服务器下载非常大的文件 (~2GB)。我已经编写了能够恢复部分完成下载的程序,

为了模拟糟糕的互联网连接,我在下载过程中一直将以太网线从路由器中拔出。不幸的是,这导致我的程序挂起以下调用: while((bytesRead = in.read(data)) > 0)

(其中 bytesRead 是一个 int,in 是从 HttpURLConnection 构建的 BufferedInputStream,data 是一个字节数组)。

我试图通过在另一个线程上调用 in.close() 来“中断”调用,但在互联网连接恢复之前它没有效果(此时抛出异常)。

有什么方法可以防止互联网连接中断冻结我的程序?

【问题讨论】:

有类似回答的问题:***.com/questions/804951/… 【参考方案1】:

我发现唯一可靠的方法是将Socket 实例化为InterruptibleChannel,并在卡住的 IO 线程上进行中断。 (顺便说一句,你不必使用带有 InterruptibleChannels 的异步 NIO 调用,阻塞 I/O 工作正常,你只是有一个非常好的和统一的方式来踢卡住的交换)

不过,URLConnection 似乎不允许您连接自定义 Socket 工厂。

也许您应该调查来自 Apache 的 HttpClient。

编辑

这是创建可中断套接字的方法。

import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.nio.channels.SocketChannel;

final SocketAddress remoteAddr =
    new InetSocketAddress(
        serverAddress,
        servicePort
    );

final SocketChannel socketChannel = SocketChannel.open( );

socketChannel.connect( remoteAddr );

// Here java.io.Socket is obtained
Socket socket = socketChannel.socket( );

我没有 HttpClient 示例,但我知道你可以自定义套接字初始化。

【讨论】:

你有这方面的例子吗?我一直在寻找很长一段时间,我一直无法找到任何有用的东西。本质上,我需要的是一种可靠、可中断、可恢复的方式来下载非常大的文件(~2gb)。我找不到任何等效于 HttpURLConnection.setRequestProperty()... @Samusaaron3。我添加了一个如何创建 interraptible 套接字的示例。【参考方案2】:

有关处理这种情况的代码,请参阅http://thushw.blogspot.com/2010/10/java-urlconnection-provides-no-fail.html

已编辑:实际上,使用setSoTimeout(如 Joop Eggen 的链接评论中所建议)设置套接字超时(以毫秒为单位)可能更好。

【讨论】:

我试过从一个单独的线程调用 .disconnect() ,但是即使在调用之后,也没有抛出 IOException,所以我仍然卡住了...... @DNA 要使用 setSoTimeout,您应该有一个 Socket,但 HttpURLConnection 不允许您检索其底层 Socket。 (我假设 OP 需要依赖 HttpURLConnection)【参考方案3】:

您的URLConnection 上有.setReadTimeout(int timeout) 吗?

-- 编辑

查看@DNA 的答案以获得简洁的解决方案:

简而言之,您可以生成一个.disconnect()s URLConnection 的并行线程(在让您的第二个线程休眠 timeout 毫秒之后),从而触发一个 IOException,它会得到你摆脱了停滞不前的阅读。

【讨论】:

这是一个很好的做法,但如果服务器返回一些数据并且 then 卡住,它就无济于事 - 它只适用于服务器根本没有返回数据的情况.

以上是关于如何终止 BufferedInputStream .read() 调用的主要内容,如果未能解决你的问题,请参考以下文章

BufferedInputStream 到 byte[] 以通过 Socket 发送到数据库

深入研究BufferedInputStream内幕

Java IO BufferedInputStream 和 BufferedOutputStream

BufferedReader 和 BufferedInputStream 的区别

bufferedinputstream的使用

BufferedInputStream 中的读取方法