15

HttpListener を使用して静的ファイルを提供しようとしていますが、これは小さなファイルでうまく機能します。ファイル サイズが大きくなると (350 MB と 600 MB のファイルでテスト)、サーバーは次いずれかの例外

停止します。セマフォのタイムアウト期間が過ぎました。

例外を取り除き、安定して信頼できる (そして高速に) 実行するには、何を変更する必要がありますか?

さらに詳しく説明します。これは基本的に、この以前の質問に対するフォローアップの質問です。コードは、効果を示すために少し拡張されています。コンテンツの書き込みは (できれば妥当な) チャンク サイズ (私の場合は 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 に答える