15

我正在尝试使用 HttpListener 来提供静态文件,这适用于小文件。当文件变大时(使用 350 和 600MB 文件进行测试),服务器会因以下异常之一而阻塞:

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

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

这里有一些进一步的阐述:这基本上是这个早先问题的后续问题。代码略微扩展以显示效果。内容写入循环使用(希望是合理的)块大小,在我的情况下为 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,但如果可能的话,更可能远离)。

4

1 回答 1

16

您没有向我们展示如何初始化 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();
    }
}
于 2012-11-14T20:13:31.280 回答