如何使用HttpURLConnection在读取InputStream时设置超时时间?

4
我有一个Java应用程序,其中我使用HttpURLConnection下载文件。 我将连接超时设置为15秒,将读取超时属性设置为1小时。 据我所知,如果服务器上的文件足够大,需要超过1小时才能下载,则会出现超时异常。 运行正常。 问题是,当我在下载正在进行(从InputStream读取缓冲区)时从客户端机器拔出互联网电缆时,下载过程不会立即终止,需要1小时(读取超时)才能中断下载。 是否有任何方法可以终止下载过程? 以下是源代码:
public class HttpDownloadUtility {
private static final int BUFFER_SIZE = 4096;
public static void downloadFile(String fileURL, String saveDir)
            throws IOException {
        URL url = new URL(fileURL);
        HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
        httpConn.setConnectTimeout(15*1000);
        httpConn.setReadTimeout(60*60*1000);
        int responseCode = httpConn.getResponseCode();

        // always check HTTP response code first
        if (responseCode == HttpURLConnection.HTTP_OK) {
            String fileName = "";
            String disposition = httpConn.getHeaderField("Content-Disposition");
            String contentType = httpConn.getContentType();
            int contentLength = httpConn.getContentLength();

            if (disposition != null) {
                // extracts file name from header field
                int index = disposition.indexOf("filename=");
                if (index > 0) {
                    fileName = disposition.substring(index + 10,
                            disposition.length() - 1);
                }
            } else {
                // extracts file name from URL
                fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
                        fileURL.length());
            }

            System.out.println("Content-Type = " + contentType);
            System.out.println("Content-Disposition = " + disposition);
            System.out.println("Content-Length = " + contentLength);
            System.out.println("fileName = " + fileName);

            // opens input stream from the HTTP connection
            InputStream inputStream = httpConn.getInputStream();
            String saveFilePath = saveDir + File.separator + fileName;

            // opens an output stream to save into file
            FileOutputStream outputStream = new FileOutputStream(saveFilePath);

            int bytesRead = -1;
            byte[] buffer = new byte[BUFFER_SIZE];
            while ((bytesRead = inputStream.read(buffer)) != -1) { //This is where the download gets stuck on some connection issues 
                outputStream.write(buffer, 0, bytesRead);
            }

            outputStream.close();
            inputStream.close();

            System.out.println("File downloaded");
        } else {
            System.out.println("No file to download. Server replied HTTP code: " + responseCode);
        }
        httpConn.disconnect();
    }
}
1个回答

2
据我所知,如果服务器上的文件太大而需要超过1小时才能下载完成,它将会因为超时异常而失败。
不是这样的。如果服务器在一个小时内无法响应任何单个读取请求,它就会失败。超时时间从您调用read()开始计算,直到接收到该读取的响应或超时期满为止。然后下一次读取将重新开始计时。总时间与此无关。你完全误解了。
工作正常。
工作正常,但不像你描述的那样。
问题在于,当我从客户端机器中拔出网络电缆时(正在从InputStream读取缓冲区时),下载进程不会立即终止,它需要1小时(读取超时)才能中断下载。
这正是它应该做的,如上所述。
有没有办法可以终止下载过程?
设置一个更短的超时时间。将其设置得足够长,以便服务器应该在该时间间隔内响应,并且足够短,使电缆拔出不会花费太长时间超时。一小时太长了。试试几分钟。

感谢EJP指正,你正确地解释了为什么需要一个小时。我将尝试使用1分钟进行测试,因为我的带宽相当高,并且我正在使用Amazon S3云作为服务器,所以我希望这应该足以进行读取请求。 - Dev_Vikram
@Dev_Vikram 超时时间与带宽几乎没有关系。它与路径延迟有关,但更多地与服务器预期服务时间以及您愿意等待的时间有关。我认为一分钟有点太短了。 - user207421
没错。我将使用15分钟,这是.NET的默认设置。再次感谢您的迅速回复。 :) - Dev_Vikram
现在太长了,我之前说的是几分钟,而且我的意思是两到三分钟。我能快速找到关于.NET读取超时的唯一信息是100秒。我很难相信它是15分钟。 - user207421
在不同的网络速度和不同的客户端上进行了测试。对我来说,2分钟似乎是最优的选择。谢谢。 - Dev_Vikram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接