2017-10-16 33 views
6

TcpListener क्लास का एक सर्वर है। यह BeginAcceptTcpClient (AsyncCallback, ऑब्जेक्ट) विधि का उपयोग कर आने वाले कनेक्शन स्वीकार करता है।एसिंक्रोनस विधि वर्तमान थ्रेड (मुख्य थ्रेड) में AsyncCallback प्रारंभ होता है

कोड उदाहरण में लिखा है MSDN

public static ManualResetEvent tcpClientConnected = 
    new ManualResetEvent(false); 

public static void DoBeginAcceptTcpClient(TcpListener 
    listener) 
{ 
    while(true) 
    { 
     tcpClientConnected.Reset(); 
     Console.WriteLine("Waiting for a connection..."); 
     listener.BeginAcceptTcpClient(
      new AsyncCallback(DoAcceptTcpClientCallback), 
      listener); 
     tcpClientConnected.WaitOne(); 
    } 
} 
public static void DoAcceptTcpClientCallback(IAsyncResult ar) 
{ 
    TcpListener listener = (TcpListener) ar.AsyncState; 
    TcpClient client = listener.EndAcceptTcpClient(ar); 
    Console.WriteLine("Client connected completed"); 
    tcpClientConnected.Set(); 
    while(true) 
    { 
     //Receiving messages from the client 
    } 
} 

समस्या यह है कि DoAcceptTcpClientCallback (IAsyncResult ar) विधि कभी कभी वर्तमान सूत्र में क्रियान्वित करने शुरू होता है (मुख्य), नहीं नया एक, और ब्लॉक यह (मुख्य)। इस वजह से, निम्नलिखित कनेक्शन प्राप्त नहीं किए जा सकते हैं। कृपया समझने में सहायता करें कि इस विधि के लिए धागा क्यों नहीं बनाएं

+0

आपने हमें नहीं दिखाया है, लेकिन मुझे लगता है कि '// क्लाइंट से संदेश प्राप्त करना' कुछ कारणों से * सिंक्रोनस * एपीआई कॉल का उपयोग करने के लिए स्विच कर रहा है। ऐसा मत करो। एक बार जब आप async (कुछ तरीकों से थ्रेड बनाने में शामिल नहीं होते हैं) तो आप नहीं जानते कि आप किस धागे पर चल रहे होंगे - इसलिए आपको केवल तब तक चलाना चाहिए जब तक कि आप अगली एसिंक विधि को प्रेषित न करें और फिर वापस आओ। –

+0

सबसे पहले, आप [AcceptTcpClientAsync] का उपयोग क्यों नहीं कर रहे हैं (https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclientasync%28v=vs.110%29.aspx?f = 255 और एमएसपीपीआरआर = -2147217396)? यह सभी समर्थित .NET संस्करणों में उपलब्ध है और एसिंक्रोनस प्रोग्रामिंग को बहुत आसान बनाता है। –

+0

दूसरा 'एसिंक्रोनस' का अर्थ 'अलग थ्रेड' नहीं है। इसका मतलब है कि आपका धागा प्रतिक्रिया के लिए इंतजार नहीं करेगा। आईओ ऑपरेशंस को एक अलग थ्रेड की भी आवश्यकता नहीं है क्योंकि विंडोज़ में आईओ हमेशा ड्राइवर स्तर पर असीमित है। एपीआई * अनुकरण * सिंगल थ्रेडेड प्रोग्रामिंग को आसान बनाने के लिए अवरुद्ध करता है –

उत्तर

2

हां, जैसा कि आपने पाया है, you're not guaranteed that your AsyncCallback is called on a new thread। असल में यदि एक एसिंक्रोनस ऑपरेशन इतनी तेज़ी से पूरा हो जाता है कि कॉलबैक को उसी थ्रेड से सिंक्रनाइज़ किया जा सकता है, तो यह होगा।

ऐसा तब होता है जब BeginXXX कॉल पुराने एसिंक मॉडल में वापस लौटना चाहते हैं, जिस चीज का आप इंतजार कर रहे हैं वह पहले ही हुआ है, उदाहरण के लिए आपके मामले में एक कनेक्शन, इसलिए अनावश्यक संदर्भ स्विच को रोकने के लिए, यह IAsyncResult.CompletedSynchronously को सत्य पर सेट करता है और आपके कॉलबैक को तुल्यकालिक रूप से निष्पादित करता है जो आपके उदाहरण में while (true) लूप में थ्रेड को असीमित रूप से अवरुद्ध करता है, इसे BeginAcceptTcpClient कॉल से वापस आने की अनुमति नहीं देता है।

आपको उस कॉलबैक विधि में उस परिदृश्य के लिए अतुल्यकालिक रहना जारी रखना चाहिए और जल्दी से लौटना जारी रखना चाहिए।

इसके अलावा, async/await का उपयोग करने में देखें, वे असीमित प्रोग्रामिंग को अधिक आसान बनाते हैं।

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