2012-11-14 8 views
11

के साथ बड़ी फ़ाइलों की सेवा करना मैं स्थिर फ़ाइलों की सेवा के लिए HttpListener का उपयोग करने की कोशिश कर रहा हूं, और यह छोटी फ़ाइलों के साथ अच्छी तरह से काम करता है। फ़ाइल आकार बड़े हो जब (350 और 600MB फाइलों के साथ परीक्षण किया गया), सर्वर ने निम्न अपवादों में से एक के साथ chokes:

HttpListenerException: आई/ओ आपरेशन या तो एक धागे से बाहर निकलें या एक आवेदन अनुरोध की वजह से रोक दी गई है, या:
HttpListenerException: सेमाफोर समय समाप्ति की अवधि समाप्त हो गया है।सी # HttpListener

अपवादों से छुटकारा पाने के लिए क्या बदलने की आवश्यकता है, और इसे स्थिर/भरोसेमंद (और तेज़) चलाने दें?

यहां कुछ और विस्तार है: यह मूल रूप से this earlier question पर एक अनुवर्ती प्रश्न है। प्रभाव को दिखाने के लिए कोड थोड़ा बढ़ाया गया है। सामग्री लेखन एक लूप में है (उम्मीदवार उचित) खंड के आकार, मेरे मामले में 64 केबी, लेकिन मूल्य बदलने से गति को छोड़कर कोई फर्क नहीं पड़ता (उल्लिखित पुराने प्रश्न देखें)।


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 का उपयोग कर कार्यक्रम में एक ब्राउज़र में डाउनलोड कोशिश कर रहा हूँ और यह भी, यह कोई फर्क नहीं पड़ता।

मेरे शोध के आधार पर, मुझे लगता है कि HttpListener वास्तव में क्लाइंट को सामग्री फ्लश करने में सक्षम नहीं है या कम से कम अपनी गति से ऐसा करता है। मैंने बाइनरीवाइटर को भी छोड़ दिया है और सीधे स्ट्रीम में लिखा है - कोई फर्क नहीं पड़ता। बेस स्ट्रीम के चारों ओर एक बुफर्डस्ट्रीम पेश किया - कोई फर्क नहीं पड़ता। मजेदार है, अगर एक थ्रेड। नींद (200) या लूप में थोड़ा बड़ा पेश किया गया है, तो यह मेरे बॉक्स पर काम करता है। हालांकि मुझे संदेह है कि यह वास्तविक समाधान के लिए पर्याप्त स्थिर है। This question इंप्रेशन देता है कि इसे सही तरीके से चलाने के लिए कोई मौका नहीं है (आईआईएस/एएसपी.नेट पर जाने के अलावा, जो मैं सहारा लेता हूं, लेकिन संभवतः यदि संभव हो तो दूर रहें)।

उत्तर

10

आपने हमें अन्य महत्वपूर्ण हिस्सा नहीं दिखाया कि आपने एचटीपी लिस्टनर को कैसे शुरू किया। इसलिए मैं नीचे एक साथ अपने कोड की कोशिश की और यह काम किया

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 को तुरंत चालू कर रहा हूं, और मुझे आपके कोड का उपयोग करके त्रुटियां मिलती हैं। बेशक मैंने अपने पर्यावरण में विभिन्न पीसी पर इसे आजमाया है और एक ही प्रभाव देखा है, लेकिन एक स्वच्छ वीएम मशीन पर, आपका कोड और मेरा मूल कार्यान्वयन दोनों बेकार ढंग से काम करते हैं। मुझे अभी तक पता नहीं है कि कारण क्या है, मुझे एंटीवायरस पर संदेह है ... तो आपकी मदद के लिए फिर से धन्यवाद! – lichtalberich

+1

@ एलबी: क्या आप कृपया बता सकते हैं कि अतिरिक्त बाइनरीवाइटर का उपयोग करने का क्या फायदा है? –

+0

प्रश्न की तुलना में यहां बड़ा अंतर क्या है? क्या आप इस मुद्दे और समाधान का सारांश दे सकते हैं? –