首页 新闻 会员 周边

超难挑战:Response.Flush()与迅雷的矛盾

2
悬赏园豆:20 [已解决问题] 解决于 2012-09-04 09:05

在asp.net中,要向客户端提供文件下载功能,经常需要用到Response.Flush();这一句代码(您说可以不用?是的,不过对大文件的下载,不用这一行,我还没有找到合理的实现方式),但是只要有这一行代码的存在,那么当客户端点击链接弹出迅雷下载并且又点击了“取消”时,问题就出来了:服务器的asp.net进程会一直处于阻塞状态,无法再响应任何操作,直到客户端退出迅雷!

 

不相信的可以试一试。我也希望这只是由于某种偶然因素导致的,而不是必然现象。

大家可有什么好的解决办法?

问题补充:

我用于下载功能的核心代码:

                #region -------添加重要响应头、解析请求头、相关验证-------------------
                httpContext.Response.Clear();
                httpContext.Response.BufferOutput = false;//此处如果设为false,会导致迅雷打开并取消后一直阻塞asp.net进程
                //httpContext.Response.AddHeader("Content-MD5", GetMD5Hash(myFile));//用于验证文件  
                httpContext.Response.AddHeader("Accept-Ranges", "bytes");//重要:续传必须  
                httpContext.Response.AppendHeader("ETag", "\"" + eTag + "\"");//重要:续传必须  
                httpContext.Response.AppendHeader("Last-Modified", lastUpdateTiemStr);//把最后修改日期写入响应                  
                httpContext.Response.ContentType = "application/octet-stream";//MIME类型:匹配任意文件类型  
                httpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" + ProcessFileName(Path.GetFileName(filePath)));
                httpContext.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
                httpContext.Response.AddHeader("Connection", "Keep-Alive");
                httpContext.Response.ContentEncoding = Encoding.UTF8;
                if (httpContext.Request.Headers["Range"] != null)
                {
                    //------如果是续传请求,则获取续传的起始位置,即已经下载到客户端的字节数------  
                    httpContext.Response.StatusCode = 206;//重要:续传必须,表示局部范围响应。初始下载时默认为200  
                    string[] range = httpContext.Request.Headers["Range"].Split(new char[] { '=', '-' });//"bytes=1474560-"  
                    startBytes = Convert.ToInt64(range[1]);//已经下载的字节数,即本次下载的开始位置    
                    if (startBytes < 0 || startBytes >= fileLength)
                    {
                        //无效的起始位置  
                        return false;
                    }
                }
                if (startBytes > 0)
                {
                    //------如果是续传请求,告诉客户端本次的开始字节数,总长度,以便客户端将续传数据追加到startBytes位置后----------  
                    httpContext.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
                }
                #endregion

                #region -------向客户端发送数据块-------------------
                br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
                int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize);//分块下载,剩余部分可分成的块数  
                for (int i = 0; i < maxCount && httpContext.Response.IsClientConnected; i++) //客户端中断连接,则暂停 
                {                     
                    httpContext.Response.BinaryWrite(br.ReadBytes(packSize));
                    //考虑取消下面一行,否则导致迅雷打开并取消后一直阻塞asp.net进程
                    httpContext.Response.Flush();
                    if (sleep > 1) System.Threading.Thread.Sleep(sleep);
                }
                #endregion
戒焦戒躁的主页 戒焦戒躁 | 初学一级 | 园豆:15
提问于:2012-09-03 11:28
< >
分享
最佳答案
0

一般Response.Flush()是自动调用的,只有按块传送时的最后一个块需要Response.Flush()来刷新并发送,因为没达到缓冲区大小

收获园豆:15
56180825 | 小虾三级 |园豆:1756 | 2012-09-03 12:10

你的说法很有道理,我试着把块大小缩小到10KB,并且取消循环中的Response.Flush()语句,似乎并不影响大文件的下载,并且也解决了迅雷取消下载造成的进程阻塞问题。但是如果像你说的那样,对最后一个块使用Response.Flush()语句,同样会造成进程阻塞问题(迅雷取消下载的话)。

能否把你的用于下载的代码给个片段?参考学习一下。谢谢!

戒焦戒躁 | 园豆:15 (初学一级) | 2012-09-03 15:12

@戒焦戒躁: 

阻塞是正常的,对方不接受数据的时候程序会一直阻塞到超时为止.你的文件大小设置有问题吧,

56180825 | 园豆:1756 (小虾三级) | 2012-09-03 19:54
其他回答(3)
0

VS里运行没发现问题,只是点取消前迅雷发了好几次请求,最后一次才取了文件大小。。。

收获园豆:4
向往-SONG | 园豆:4853 (老鸟四级) | 2012-09-03 13:30

你下载代码中使用了Response.Flush()的?迅雷取消后你的应用程序还可以继续响应操作吗?

支持(0) 反对(0) 戒焦戒躁 | 园豆:15 (初学一级) | 2012-09-03 15:31
0

貌似用谷歌 火狐浏览器的时候迅雷好像不会自己启动

收获园豆:1
隔壁王叔 | 园豆:4 (初学一级) | 2012-09-03 16:10
0

我想在我的程序中采用你的代码,可否将上述代码完整的发送给我一份?不胜感激。邮箱:coolmanlee@foxmail.com

coolmanlee | 园豆:202 (菜鸟二级) | 2012-12-06 12:20
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册