使用C#HttpListener服务大文件
我正在尝试使用HttpListener来服务静态文件,这对小文件很有效。当文件大小变大时(使用350和600MB文件测试),服务器会因以下异常之一而阻塞:使用C#HttpListener服务大文件,c#,httplistener,C#,Httplistener,我正在尝试使用HttpListener来服务静态文件,这对小文件很有效。当文件大小变大时(使用350和600MB文件测试),服务器会因以下异常之一而阻塞: HttpListenerException:由于线程退出或应用程序请求,I/O操作已中止,或者: HttpListenerException:信号量超时时间已过期 为了消除异常并让它稳定/可靠(快速)运行,需要做哪些更改 这里有一些进一步的阐述:这基本上是一个后续问题。代码稍微扩展以显示效果。内容编写是一个循环(希望是合理的),在我的例子中,
HttpListenerException:由于线程退出或应用程序请求,I/O操作已中止,或者:
HttpListenerException:信号量超时时间已过期 为了消除异常并让它稳定/可靠(快速)运行,需要做哪些更改 这里有一些进一步的阐述:这基本上是一个后续问题。代码稍微扩展以显示效果。内容编写是一个循环(希望是合理的),在我的例子中,块大小为64kB,但是更改值除了速度之外没有任何区别(请参阅前面提到的问题) 我尝试在浏览器和使用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)代码>已删除
如果你想看到它的完整代码
啊!我不得不承认,我陷入了一种痴迷,认为HttpListener可能会有一些问题,而不是仅仅清楚地思考。所以@L.B谢谢你让我重回正轨。基本上,我是以同样的方式实例化HttpListener的,我确实使用您的代码得到了错误。当然,我已经在我们环境中的不同PC上试用过,并看到了相同的效果,但在干净的VM机器上,您的代码和我的原始实现都可以完美地工作。我还没有找到原因,我怀疑是病毒。。。再次感谢你的帮助@L.B.:你能说明使用额外的二进制编写器有什么好处吗?与这个问题相比,这里有什么大的不同?你能总结一下问题和解决方案吗?
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);
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();
}
}