我正在尝试使用HttpListener来提供静态文件,这适用于小文件。当文件大小变大(使用350和600MB文件测试)时,服务器会出现以下例外情况之一的窒息:
HttpListenerException :由于线程退出或应用程序请求,I / O操作已中止,或者:
HttpListenerException :信号量超时期限已过期。
需要改变什么才能摆脱异常,让它运行稳定/可靠(快速)?
以下是一些进一步的阐述:这基本上是this earlier question的后续问题。稍微扩展代码以显示效果。内容写入是一个循环(希望是合理的)块大小,在我的情况下是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)或稍大,它可以在我的盒子上工作。但是我怀疑它是否足够稳定以获得真正的解决方案。 This question给人的印象是没有机会让它正常运行(除了转移到IIS / ASP.NET,我会诉诸,但如果可能的话,更可能远离它)。
答案 0 :(得分:14)
您没有向我们展示如何初始化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();
}
}