2012-11-14 53 views
11

我試圖使用HttpListener來提供靜態文件,並且這對小文件很好。當文件大小變大(用350和600MB文件測試)時,服務器扼流圈出現以下情況之一:

HttpListenerException由於線程退出或應用程序請求,I/O操作已中止,或:
HttpListenerException信號燈超時時間已過期用C#提供大文件HttpListener

什麼需要改變,以擺脫例外,讓它運行穩定/可靠(和快速)?

這裏有一些進一步的闡述:這基本上是對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,但更可能遠離可能)。

回答

10

您沒有向我們展示如何初始化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(); 
    } 
} 
+0

衛生署!我不得不承認,我已經陷入困境,認爲HttpListener可能存在一些問題,而不是僅僅考慮清楚。所以@ L.B謝謝你讓我回到正確的軌道上。基本上我以相同的方式實例化HttpListener,並且使用您的代碼獲取錯誤。當然,我已經在我們的環境中的不同PC上試用了它,並且看到了相同的效果,但是在乾淨的VM機器上,您的代碼和我的原始實現都完美無瑕。我還沒有找出原因是什麼,我懷疑AntiVirus ...所以再次感謝您的幫助! – lichtalberich

+1

@ L.B。:您能否說明使用額外的BinaryWriter有哪些優勢? –

+0

這個問題與這個問題相比有什麼重大區別?你能總結一下這個問題和解決方案嗎? –