2012-01-27 10 views
11

के साथ एकाधिक अनुरोधों को संभालने में मेरे पास एक .NET विंडोज सेवा है जो एक धागे को जन्म देती है जो मूल रूप से केवल HttpListener के रूप में कार्य करती है। यह तुल्यकालिक मोड उदाहरण में ठीक समस्या मैं अब काम कर रहा है ...सी # एचटीपी लिस्टनर

private void CreateLListener() 
{ 
    HttpListenerContext context = null; 
    HttpListener listener = new HttpListener(); 
    bool listen = true; 

    while(listen) 
    { 
     try 
     { 
      context = listener.GetContext(); 
     } 
     catch (...) 
     { 
      listen = false; 
     } 
     // process request and make response 
    } 
} 

मैं इस से अधिक अनुरोध के साथ काम करने की जरूरत है और उन्हें जवाब दिया है करने के लिए एक साथ या कम से कम एक ओवरलैप तरीके से।

आगे की व्याख्या करने के लिए - क्लाइंट एक मीडिया प्लेयर ऐप है जो अनुरोध हेडर प्रॉपर्टी Range bytes=0- के साथ मीडिया फ़ाइल के लिए अनुरोध करके शुरू होता है। जहां तक ​​मैं यह कह सकता हूं कि मीडिया कंटेनर क्या है, यह काम करने के लिए यह करता है।

इसके बाद 'चंक' पढ़ा गया है (या यदि यह मीडिया प्रकार का पता लगाने के लिए पर्याप्त पढ़ा गया है) तो यह Range bytes=X-Y के साथ एक और अनुरोध (एक अलग क्लाइंट सॉकेट नंबर से) बनाता है। इस मामले में वाई पहली प्रतिक्रिया में सामग्री-लंबाई लौटा दी गई है और एक्स उससे 250000 बाइट कम है (आईआईएस का परीक्षण के रूप में उपयोग किया गया है)। इस स्तर पर यह देखने के लिए आखिरी 'खंड' प्राप्त हो रहा है कि क्या यह गेज लंबाई के लिए मीडिया टाइम-स्टैंप प्राप्त कर सकता है।

इसे पढ़ने के बाद, यह मीडिया फ़ाइल को ठीक से स्ट्रीम करने के लिए Range bytes=0- (किसी अन्य सॉकेट नंबर से) के साथ एक और अनुरोध करता है।

किसी भी समय, यदि ग्राहक का उपयोगकर्ता 'छोड़ें' ऑपरेशन करता है तो यह Range bytes=Z- के साथ एक और अनुरोध (अभी तक एक और सॉकेट नंबर से) भेजता है जहां ज़ेड मीडिया फ़ाइल में कूदने की स्थिति है।

मैं HTTP सामान के साथ बहुत अच्छा नहीं हूं लेकिन जहां तक ​​मैं कह सकता हूं कि मुझे सुनने के लिए मूल HttpListener मूल अनुमति देने के दौरान प्रत्येक अनुरोध/प्रतिक्रिया को संभालने के लिए कई धागे का उपयोग करने की आवश्यकता है। मैंने बहुत सारी खोज की है लेकिन फिट होने के लिए एक मॉडल नहीं मिल रहा है।

संपादित करें:

निम्न उदाहरण जो मैं अपने आवश्यकताओं के अनुरूप करने के लिए अनुकूलित करने में सक्षम था की पावती और रिक Strahl के लिए आभार ...

Add a Web Server to your .NET 2.0 app with a few lines of code

उत्तर

12

यदि आपको BeginGetContext के लिए एक और आसान विकल्प की आवश्यकता है, तो आप मुख्य थ्रेड पर उन्हें निष्पादित करने के बजाय थ्रेडपूल में नौकरियां कतारबद्ध कर सकते हैं।इस तरह की तरह:

private void CreateLListener() { 
    //.... 
    while(true) { 
     ThreadPool.QueueUserWorkItem(Process, listener.GetContext());  
    } 
} 
void Process(object o) { 
    var context = o as HttpListenerContext; 
    // process request and make response 
} 
+2

इसे करने के लिए बिल्कुल सही तरीका है, लेकिन Async प्रोग्रामिंग के साथ पकड़ने के लिए आपको बेहतर –

10

आप async उपयोग करने की आवश्यकता कई अनुरोधों को संसाधित करने में सक्षम होने के लिए विधि। तो आप ई BeginGetContext और EndGetContext विधियों का उपयोग करेंगे।

here पर एक नज़र डालें।

तुल्यकालिक मॉडल उपयुक्त होगा और यदि आपके आवेदन ब्लॉक चाहिए, जबकि एक ग्राहक के अनुरोध के लिए इंतज़ार कर आप एक समय पर केवल एक * अनुरोध पर कार्रवाई करना चाहते हैं *। सिंक्रोनस मॉडल का उपयोग करके, GetContext विधि को कॉल करें, जो किसी ग्राहक को अनुरोध भेजने के लिए प्रतीक्षा करता है। जब कोई होता है तो प्रसंस्करण के लिए विधि एक HttpListenerContext ऑब्जेक्ट देता है।

+0

Async (जाहिर है) सिंक करने के लिए अलग तरह से काम करता है। शुरू करने के लिए कॉल तुरंत वापस आ जाएगा, इसलिए आपको इसका सामना करना होगा, इसलिए अधिकांश ऐप्स में कुछ प्रकार का वेटोन होता है। हालांकि यह अवरुद्ध नहीं होगा। जब आप कॉल करते हैं तो आपके द्वारा निर्दिष्ट कॉलबैक एक नए थ्रेड पर निष्पादित होगा। वहां के भीतर आप सुनने के लिए फिर से शुरू करके अंत में कॉल करें और फिर आप अपना काम करें। नए अनुरोधों को नए धागे पर तब तक संभाला जाता है जब तक आप सुनना बंद नहीं करते। –

+2

@MisterSquonk ने प्रसन्न किया कि यह आपके लिए काम करता है। हम यहाँ मछली नहीं देते हैं, लेकिन मछली पकड़ने सिखाते हैं। :) – Aliostad

5

आप यहाँ भविष्य से कर रहे हैं और async/इंतजार का उपयोग कर किसी एकल थ्रेड के साथ कई समवर्ती अनुरोधों को हैंडल करने की कोशिश कर रहा है, तो ..

public async Task Listen(string prefix, int maxConcurrentRequests, CancellationToken token) 
{ 
    HttpListener listener = new HttpListener(); 
    listener.Prefixes.Add(prefix); 
    listener.Start(); 

    var requests = new HashSet<Task>(); 
    for(int i=0; i < maxConcurrentRequests; i++) 
     requests.Add(listener.GetContextAsync()); 

    while (!token.IsCancellationRequested) 
    { 
     Task t = await Task.WhenAny(requests); 
     requests.Remove(t); 

     if (t is Task<HttpListenerContext>) 
     { 
      var context = (t as Task<HttpListenerContext>).Result; 
      requests.Add(ProcessRequestAsync(context)); 
      requests.Add(listener.GetContextAsync()); 
     } 
    } 
} 

public async Task ProcessRequestAsync(HttpListenerContext context) 
{ 
    ...do stuff... 
} 
+1

सर्वर पर पहुंचाएगा यदि आप ProcessRequestAsync से अपवादों की परवाह करते हैं, और आपको ध्यान रखना चाहिए, तो किसी अन्य शाखा में t.Wait() को कॉल करना न भूलें। सब कुछ मुझे इस दृष्टिकोण +1 पसंद है। – frast

+0

एक और समस्या यह है कि थोड़ी सी स्थिति केवल तभी जांच की जाती है जब किसी एक कार्य पूर्ण हो जाए। – frast

+0

क्या आप विस्तार कर सकते हैं कि क्यों केवल जब कोई समस्या @frast की समस्या है? – LightLabyrinth