使用C#HttpListener提供大型文件

我正在尝试使用HttpListener来提供静态文件,这适用于小文件。 当文件大小变大(使用350和600MB文件测试)时,服务器会出现以下exception之一:

HttpListenerException由于线程退出或应用程序请求I / O操作已中止 ,或者:
HttpListenerException信号量超时期限已过期

什么需要改变以摆脱exception,让它运行稳定/可靠(和快速)?

这里有一些进一步的阐述:这基本上是对这个早期问题的后续问题 。 稍微扩展代码以显示效果。 内容写入是一个循环(希望是合理的)块大小,在我的情况下是64kB,但是改变值除了速度之外没有区别(参见上面提到的旧问题)。

using( FileStream fs = File.OpenRead( @"C:\test\largefile.exe" ) ) { //response is HttpListenerContext.Response... response.ContentLength64 = fs.Length; response.SendChunked = false; response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet; response.AddHeader( "Content-disposition", "attachment; filename=largefile.EXE" ); byte[] buffer = new byte[ 64 * 1024 ]; int read; using( BinaryWriter bw = new BinaryWriter( response.OutputStream ) ) { while( ( read = fs.Read( buffer, 0, buffer.Length ) ) > 0 ) { Thread.Sleep( 200 ); //take this out and it will not run bw.Write( buffer, 0, read ); bw.Flush(); //seems to have no effect } bw.Close(); } response.StatusCode = ( int )HttpStatusCode.OK; response.StatusDescription = "OK"; response.OutputStream.Close(); } 

我正在尝试使用HttpWebRequest在浏览器和C#程序中进行下载,它没有任何区别。

根据我的研究,我认为HttpListener实际上无法将内容刷新到客户端,或者至少按照自己的节奏这样做。 我也省略了BinaryWriter并直接写入流 – 没有区别。 在基本流周围引入了BufferedStream – 没有区别。 有趣的是,如果循环中引入了Thread.Sleep(200)或稍大,它可以在我的盒子上运行。 但是我怀疑它是否足够稳定以获得真正的解决方案。 这个问题给人的印象是,没有机会让它正常运行(除了转移到IIS / ASP.NET,我会诉诸,但如果可能的话,更可能远离它)。

您没有向我们展示如何初始化HttpListener的其他关键部分。 因此,我尝试使用下面的代码进行操作

 HttpListener listener = new HttpListener(); listener.Prefixes.Add("http://*:8080/"); listener.Start(); Task.Factory.StartNew(() => { while (true) { HttpListenerContext context = listener.GetContext(); Task.Factory.StartNew((ctx) => { WriteFile((HttpListenerContext)ctx, @"C:\LargeFile.zip"); }, context,TaskCreationOptions.LongRunning); } },TaskCreationOptions.LongRunning); 

WriteFile是你的代码,其中Thread.Sleep( 200 ); 已移除。

如果你想看到它的完整代码。


 void WriteFile(HttpListenerContext ctx, string path) { var response = ctx.Response; using (FileStream fs = File.OpenRead(path)) { string filename = Path.GetFileName(path); //response is HttpListenerContext.Response... response.ContentLength64 = fs.Length; response.SendChunked = false; response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet; response.AddHeader("Content-disposition", "attachment; filename=" + filename); byte[] buffer = new byte[64 * 1024]; int read; using (BinaryWriter bw = new BinaryWriter(response.OutputStream)) { while ((read = fs.Read(buffer, 0, buffer.Length)) > 0) { bw.Write(buffer, 0, read); bw.Flush(); //seems to have no effect } bw.Close(); } response.StatusCode = (int)HttpStatusCode.OK; response.StatusDescription = "OK"; response.OutputStream.Close(); } }