2010-12-08 12 views
7

मुझे NetworkStream से पढ़ने की आवश्यकता है जो डेटा को यादृच्छिक रूप से भेज देगा और डेटा पैकेट का आकार भी अलग-अलग रहेगा। मैं एक बहु थ्रेडेड एप्लिकेशन को कार्यान्वित कर रहा हूं जहां प्रत्येक धागे से पढ़ने के लिए अपनी स्ट्रीम होगी। यदि स्ट्रीम पर कोई डेटा नहीं है, तो एप्लिकेशन को डेटा आने की प्रतीक्षा करनी चाहिए। हालांकि, यदि सर्वर डेटा भेज रहा है और सत्र समाप्त कर दिया गया है, तो इसे बाहर निकलना चाहिए।NetworkStream.Read() और NetworkStream.BeginRead() के बीच अंतर?

प्रारंभ में मैंने स्ट्रीम से डेटा प्राप्त करने के लिए Read विधि का उपयोग किया था, लेकिन यह थ्रेड को अवरुद्ध करने और स्ट्रीम पर डेटा दिखाई देने तक प्रतीक्षा करता था।

MSDN पर प्रलेखन पता चलता है,

तो कोई डेटा पढ़ने के लिए उपलब्ध है, पढ़ें विधि देता है 0. दूरस्थ होस्ट कनेक्शन, बंद हो जाता है और सभी उपलब्ध डेटा किया गया है प्राप्त करते हैं , रीड विधि तुरंत पूर्ण करती है और शून्य बाइट्स लौटाती है।

लेकिन मेरे मामले में, मुझे Read विधि 0 वापस करने और कृपा से बाहर निकलने के लिए कभी नहीं मिला है। यह बस अनिश्चित काल तक इंतजार कर रहा है।

मेरी आगे की जांच में, मैं BeginRead पर आया जो धारा को देखता है और जैसे ही यह डेटा प्राप्त करता है, कॉलबैक विधि को अतुल्यकालिक रूप से आमंत्रित करता है। मैंने इस दृष्टिकोण का उपयोग करके विभिन्न कार्यान्वयनों को भी देखने की कोशिश की है, हालांकि, BeginRead का उपयोग करने पर मैं Read के विपरीत लाभकारी होने पर पहचानने में असमर्थ था।

जैसा कि मैंने इसे देखा है, BeginRead में एसिंक कॉल होने का सिर्फ लाभ है, जो वर्तमान धागे को अवरुद्ध नहीं करेगा। लेकिन मेरे आवेदन में, मेरे पास स्ट्रीम से डेटा को पढ़ने और संसाधित करने के लिए पहले से ही एक अलग धागा है, जिससे मेरे लिए बहुत अंतर नहीं आएगा।

  • किसी को भी कृपया मदद कर सकते हैं मुझे BeginRead लिए प्रतीक्षा करें और बाहर निकलें प्रणाली को समझने और यह कैसे Read से अलग है?

  • वांछित कार्यक्षमता को लागू करने का सबसे अच्छा तरीका क्या होगा?

+0

क्या आप वाकई रिमोट साइड कनेक्शन को बंद कर रहे हैं? मुझे 'रीड' वापस लौटने में कोई समस्या नहीं है। आपका दृष्टिकोण अन्यथा सही दिशा प्रतीत होता है। –

+0

@ मैथ्यू वैसे, ईमानदारी से, मैं निश्चित रूप से यह नहीं कह सकता। यह एक तीसरी पार्टी सेवा है जिसे हम पढ़ रहे हैं। उन्होंने शटडाउन समय निर्दिष्ट किया है और हम मानते हैं कि यह उल्लेख के अनुसार होता है। मैं सिर्फ उन्हें झंडा उठाने से पहले अपने अंत में जांचना और दोबारा जांचना चाहता हूं। –

उत्तर

10

मैं BeginRead उपयोग करें, लेकिन धागा का उपयोग कर एक WaitHandle अवरोधित करना जारी रखें:

byte[] readBuffer = new byte[32]; 
var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length, 
    null, null); 

WaitHandle handle = asyncReader.AsyncWaitHandle; 

// Give the reader 2seconds to respond with a value 
bool completed = handle.WaitOne(2000, false); 
if (completed) 
{ 
    int bytesRead = stream.EndRead(asyncReader); 

    StringBuilder message = new StringBuilder(); 
    message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead)); 
} 

मूल रूप से यह async का समय समाप्त WaitHandle का उपयोग कर पढ़ता है की अनुमति देता है और आप एक बूलियन मान (completed) अगर देता है पढ़ा गया समय में पूरा किया गया था (2000 इस मामले में)।

यहाँ मेरी पूर्ण धारा पढ़ने की नकल की और मेरी विंडोज मोबाइल परियोजनाओं में से एक से चिपकाया कोड है:

private static bool GetResponse(NetworkStream stream, out string response) 
{ 
    byte[] readBuffer = new byte[32]; 
    var asyncReader = stream.BeginRead(readBuffer, 0, readBuffer.Length, null, null); 
    WaitHandle handle = asyncReader.AsyncWaitHandle; 

    // Give the reader 2seconds to respond with a value 
    bool completed = handle.WaitOne(2000, false); 
    if (completed) 
    { 
     int bytesRead = stream.EndRead(asyncReader); 

     StringBuilder message = new StringBuilder(); 
     message.Append(Encoding.ASCII.GetString(readBuffer, 0, bytesRead)); 

     if (bytesRead == readBuffer.Length) 
     { 
      // There's possibly more than 32 bytes to read, so get the next 
      // section of the response 
      string continuedResponse; 
      if (GetResponse(stream, out continuedResponse)) 
      { 
       message.Append(continuedResponse); 
      } 
     } 

     response = message.ToString(); 
     return true; 
    } 
    else 
    { 
     int bytesRead = stream.EndRead(asyncReader); 
     if (bytesRead == 0) 
     { 
      // 0 bytes were returned, so the read has finished 
      response = string.Empty; 
      return true; 
     } 
     else 
     { 
      throw new TimeoutException(
       "The device failed to read in an appropriate amount of time."); 
     } 
    } 
} 
+0

धन्यवाद @ जेनरिक टाइप टाइप, यह एक दिलचस्प दृष्टिकोण की तरह दिखता है, लेकिन मेरे लिए सही टाइमआउट अवधि निर्धारित करने का कोई तरीका नहीं है। फिर भी, मुझे लगता है कि यह मेरी समस्या के समाधान के लिए थोड़ा सा संशोधित किया जा सकता है। यदि सफल हो तो मैं कोशिश करूँगा और रिपोर्ट करूंगा। बीटीडब्ल्यू, आपके हैंडल ने मुझे मुस्कुराया .. :) –

+1

अगर मुझे गलत नहीं लगता है तो आपको हमेशा प्रत्येक BeginABC कॉल पर एंडएबीसी को कॉल करना होगा। उपर्युक्त कोड में, यदि कोई टाइमआउट है, तो अंत कभी नहीं बुलाया जाता है। कॉलबैक जो एंड (और किसी भी संभावित अपवाद को संभालता है) को कॉल करता है, शायद उपरोक्त कोड में जोड़ा जाना चाहिए। – SpeksETC

+0

@ स्पीक्सईटीसी - मुझे लगता है कि आप गलत हैं। मैं हमेशा एक अंत कहता हूं: int बाइट्स रीड = स्ट्रीम। एंड्रैड (asyncReader) ;, लेकिन शायद मुझे लाइन कोड को पूरा करने के बाद कोड को कॉल करने के लिए कोड को बदलना चाहिए = हैंडल.एटऑन (2000, झूठा); डुप्लिकेशन को हटाने के लिए। – GenericTypeTea

4

Async आई/ओ कम धागे में आई/ओ की एक ही राशि प्राप्त करने के लिए इस्तेमाल किया जा सकता।

जैसा कि आप ध्यान देते हैं, अभी आपके ऐप में प्रति स्ट्रीम एक थ्रेड है।यह कनेक्शन की छोटी संख्या के साथ ठीक है, लेकिन अगर आपको एक बार में 10000 का समर्थन करने की आवश्यकता है तो क्या होगा? Async I/O के साथ, यह अब आवश्यक नहीं है क्योंकि पढ़ने पूर्ण समापन कॉलबैक प्रासंगिक स्ट्रीम की पहचान करने के संदर्भ को पारित करने की अनुमति देता है। आपका पठन अब ब्लॉक नहीं है, इसलिए आपको प्रति स्ट्रीम एक थ्रेड की आवश्यकता नहीं है।

चाहे आप सिंक या एसिंक I/O का उपयोग करते हैं, प्रासंगिक API रिटर्न कोड पर स्ट्रीम बंद होने का पता लगाने और प्रबंधित करने का एक तरीका है। BeginRead सॉकेट को पहले ही बंद कर दिया गया है IOException के साथ विफल होना चाहिए। आपके एसिंक पढ़ने के दौरान एक बंद होने पर एक कॉलबैक ट्रिगर होगा, और EndRead तब आपको खेल की स्थिति बताएगा।

आपका आवेदन BeginRead, कॉल जब तक डेटा प्राप्त है या कोई त्रुटि होती है, और फिर प्रणाली निर्दिष्ट कॉलबैक विधि निष्पादित करने के लिए एक अलग थ्रेड उपयोग करेगा, और EndRead पर ब्लॉक प्रणाली इंतजार करेंगे तक प्रदान किया गया नेटवर्कस्ट्रीम डेटा पढ़ता है या अपवाद फेंकता है।

+0

धन्यवाद @ स्टेव। प्रति थ्रेड एक थ्रेड कई अन्य डिज़ाइन विचारों के कारण है और वास्तव में कोई मुद्दा नहीं है। हम अधिकतम पर 10 एक साथ धागे होंगे। –

0

BeginRead एक एसिंक प्रक्रिया है जिसका अर्थ है कि आपका मुख्य धागा निष्पादन शुरू हो जाएगा एक और प्रक्रिया में पढ़ें। तो अब हमारे पास 2 समांतर प्रक्रियाएं हैं। यदि आप परिणाम प्राप्त करना चाहते हैं, तो आपको एंड्रैड को कॉल करना होगा, जो परिणाम देगा।

कुछ psudo

BeginRead() 
//...do something in main object while result is fetching in another thread 
var result = EndRead(); 

लेकिन अपने मुख्य थ्रेड कुछ और करने की नहीं है, तो और यू परिणाम की जरूरत है, यू पढ़ें फोन करना चाहिए।

+2

निहितार्थ कि कई प्रक्रियाएं यहां शामिल हैं पूरी तरह से गलत है। –

+0

@ स्टीव, मुझे लगता है कि @ बोन्सिंगटन का अर्थ 'थ्रेड' था, जब उसने 'प्रक्रिया' कहा था। –

0

क्या आपने सर्वर का प्रयास किया था। ReceiveTimeout? आप उस समय को सेट कर सकते हैं जो रीड() फ़ंक्शनटन शून्य लौटने से पहले डेटा को इनकमिंग डेटा के लिए इंतजार करेगा। आपके मामले में, यह संपत्ति शायद कहीं अनंत पर सेट है।

संबंधित मुद्दे