很简单的web文件下载,只有一个servlet,用户请求的量比较大。调试发现,当下载提示框弹出后,在向response.getOutputstream().write()的时候,暂停了。

byte[] buffer = new byte[SIZE];
byteread = bis.read(buffer);
while (-1 != byteread) {
     System.out.println("count="+count++);
     System.out.println("aaaaaaa");

                           bos.write(buffer, 0, byteread); //A
                           
                           System.out.println("bbbbbbb");
byteread = bis.read(buffer);
}
bos.flush();
bos.close();
代码没有问题,文件可以下载,仅仅 当弹出下载对话框后,我没有立即去点击“下载” 或者“保存” 按钮,就发现
servlet 阻塞在上面代码的A处,直到我点击“下载”按钮或者“保存”按钮,才继续执行,并释放掉servlet所用的线程。
如果,我一直不点击,后台就会报“Connection reset by peer: socket write error”异常。
问题是,我原来总以为,弹出框体后,servlet线程,就执行完毕了,现在居然发现是这样子的,难道 一弹出下载框,servlet就会被阻塞,还是我的代码有问题呢??请各位大大讲解一下。
                  InputStream bis = null;
OutputStream bos = null;
try {
ServletOutputStream sos = response.getOutputStream();
bis = new BufferedInputStream(new FileInputStream(filePath));
bos = new BufferedOutputStream(sos);
byte[] buffer = new byte[4096];
// 清空response
                  response.reset();
                  response.setContentType("application/octet-stream;charset=gbk");
     response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
     response.addHeader("Content-Length", "" + (int)new File(filePath).length());
     response.flushBuffer();
     response.setStatus(response.SC_OK);
      System.out.println("文件读取开始");
     int byteread = 0;
     byteread = bis.read(buffer);
     while (-1 != byteread) {
         System.out.println("aaaaaaa");
bos.write(buffer, 0, byteread);//弹出下载框后,就会阻塞在这里
System.out.println("bbbbbbb");
byteread = bis.read(buffer);
}
                 bos.flush();
                 bos.close();
             
} catch (Exception e) {
System.out.println("error:" + fileName);
e.printStackTrace();
} finally {
if (bis != null) {
bis.close();
}
if (bos != null) {
bos.close();
}
}
System.out.println(fileName + "文件下载完毕.");

解决方案 »

  1.   

    本来就是这样的。因为服务器端(Servlet)不可能一下子就把所有东西输出给浏览器,服务器的发送缓存区没那么大,浏览器的接收缓存区也没那么大,网络也有传输时延(本地测试可忽略)。因此Servlet一直要服务到所有数据输出完(输出到Buffer中也算)。
      

  2.   

    能不能给我点资料或者链接让我看看呢? 谢谢 因为,我这个里的question不是文件能不能下载的问题,而是在大的并发请求下,servlet的线程被阻塞,导致服务器Http线程池被堵塞掉。表现出来的就是服务器反应很慢, 因为看了您的看法,我是这样分析的:我这里的文件容量不是很大,最大不超过20M吧,但是同一时间访问的人比较多,如果网络条件很差,当弹出下载框后下载速度很慢,客户端就可能会点击“取消”按钮,这样一来,servlet就阻塞掉了,因为 它要等到服务器来释放掉。能不能为我补充几句啊?
      

  3.   

    所以你看不少大规模的下载网站,都是直接把下载资源放在Apache之类的服务器上(也可称为下载服务器),Servlet并不直接提供下载,而是直接重定向到下载服务器上。如果你实在不想大规模调整程序,可以多分配些执行线程池;或者把提供下载的Servlet单独配置执行线程池,避免阻塞全部(但这个要中间件支持才行,比如Weblogic就能支持)。
      

  4.   

    从网上查询来的资料显示,我试了一下 用火狐浏览器,也是弹出下载框后,没有直接点击下载。但是却发现每次servlet都没有阻塞住,很流畅的运行完毕。(直接将文件读取并全部发送过来)但是用Ie8每次操作,都直接卡住了,难道和浏览器也有关系? 我觉得客户端不应该也不可能来对服务器端直接控制吧
      

  5.   

    我们网站是把下载文件用php处理,其他的请求还是servlet,感觉php在这方面的性能优于java。
      

  6.   


    问题不是服务器端,你还是木搞懂,是浏览器端。火狐的缺省缓存大,也就是它在等你点击下载的时候,可以先把服务器端想发送过来的数据全部缓存起来。
    IE的缺省缓存小,比如只有4K(只是比如),那么它在等你点击下载的时候,4K空间早就满了,服务器端再想发送数据,这边就不接收了,那么服务器端就阻塞在发送那里了。