2011-11-17 11 views
6

को अवरुद्ध नहीं करता है हाल ही में मैंने .NET सिंक्रोनस प्राप्त विधि का अजीब व्यवहार किया है। मुझे एक ऐसे एप्लिकेशन को लिखने की ज़रूरत है जिसमें नोड्स हों जो डेटा भेजकर/प्राप्त करके एक-दूसरे के साथ संवाद कर सकें। प्रत्येक सर्वर में एक रसीद लूप होता है जो एक क्रमबद्ध वर्ग प्राप्त करने के बाद सिंक्रोनस होता है, जो इसे deserializes और संसाधित करता है। उसके बाद यह इस क्रमबद्ध कक्षा को कुछ चुने हुए नोड्स (AsynchSendTo का उपयोग करके) के रूप में असीमित रूप से भेजता है।.NET C# सिंक्रोनस रिसीव

MSDN स्पष्ट रूप से कहा गया है कि:

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

मेरे मामले में यह सच नहीं है। कुछ यादृच्छिक मामले हैं जब रिसीव ब्लॉक स्थापित नहीं करता है और कनेक्शन स्थापित करने के तुरंत बाद 0 बाइट्स (गैर-निर्धारक अभिवादन) देता है। मुझे 100% यकीन है कि प्रेषक 1000 बाइट्स पर भेज रहा था। एक और मजेदार तथ्य: जब सब कुछ प्राप्त करने से पहले नींद (500) डालने पर बस ठीक काम करता है।

_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
try 
{ 
    _listener.Bind(_serverEndpoint); 
    _listener.Listen(Int32.MaxValue); 
    while (true) 
    { 
     Console.WriteLine("Waiting for connection..."); 
     Socket handler = _listener.Accept(); 

     int totalBytes = 0; 
     int bytesRec; 
     var bytes = new byte[DATAGRAM_BUFFER]; 
     do 
     { 
      //Thread.Sleep(500); 
      bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 
      totalBytes += bytesRec; 
     } while (bytesRec > 0); 

     handler.Shutdown(SocketShutdown.Both); 
     handler.Close(); 
    } 
} 
catch (SocketException e) 
{ 
    Console.WriteLine(e); 
} 

इसके अलावा भेजने हिस्सा:

public void AsynchSendTo(Datagram datagram, IPEndPoint recipient) 
{ 

    byte[] byteDatagram = SerializeDatagram(datagram); 
    try 
    { 
     var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     socket.BeginConnect(recipient, ConnectCallback, new StateObject(byteDatagram, byteDatagram.Length, socket)); 
    } 
    catch (SocketException e) 
    { 
     Console.WriteLine(e); 
    } 
} 

public void ConnectCallback(IAsyncResult result) 
{ 
    try 
    { 
     var stateObject = (StateObject)result.AsyncState; 
     var socket = stateObject.Socket; 
     socket.EndConnect(result); 
     socket.BeginSend(stateObject.Data, 0, stateObject.Data.Length, 0, new AsyncCallback(SendCallback), socket); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine("catched!" + ex.ToString()); 
    } 
} 

public void SendCallback(IAsyncResult result) 
{ 
    try 
    { 
     var client = (Socket)result.AsyncState; 
     client.EndSend(result); 
     client.Shutdown(SocketShutdown.Both); 
     client.Close(); 
    } 
    catch (Exception ex) 
    { 
     Console.WriteLine(ex); 
    } 
} 

class StateObject 
{ 
    public Byte[] Data { get; set; } 
    public int Size; 
    public Socket Socket; 
} 

मेरा प्रश्न: मैं तुल्यकालिक उपयोग कर रहा हूँ एक गलत तरीके से प्राप्त इसके अंतर्गत प्राप्त कोड है? डेटा प्राप्त करने के बावजूद यह घटना को अवरुद्ध क्यों नहीं करता है?

+0

चूंकि आपका प्रश्न विशेष रूप से उस समस्या के बारे में नहीं है जिसे आप पढ़ने से पहले नींद के साथ हल कर रहे हैं। आधे सेकेंड के बाद से प्रत्येक लूप वास्तव में विलंबता के साथ एक टोल ले सकता है यदि एक बार में बहुत कुछ पढ़ा जा रहा है, तो क्या आपने 100msecs जैसे छोटे नींद के समय के साथ पढ़ने के बाद सोने की कोशिश की है? इसने सीरियल बंदरगाहों से पढ़ने के लिए मेरे लिए काम किया है, लेकिन यह भी तब हुआ जब एक डेटा प्राप्त हुआ घटना भी हुई। – jlafay

+0

यह सॉकेट काम करने का तरीका नहीं है। सभी प्रयास/पकड़ ब्लॉक को हटाकर इसका निदान करना प्रारंभ करें। –

उत्तर

4

आप अपने आप को पैर में शूटिंग कर रहे हैं।

bytesRec = handler.Receive(bytes, totalBytes, handler.Available, SocketFlags.None); 

कनेक्शन के बहुत शुरुआत में, Available 0 हो जाएगा, यह इसके बजाय 0. के साथ तुरंत वापस जाने के लिए मजबूर कर रहा है, तो आप बाइट्स जो अपने बफर में स्वतंत्र हैं (जैसे bytes.Length-totalBytes) की संख्या है, यह निर्दिष्ट करना चाहिए तो ब्लॉक भी करेगा।

6

आपके यहां एक सहमति समस्या हो सकती है। कनेक्शन स्वीकार करने के बाद, आप सीधे प्राप्त करने के लिए कूदते हैं। प्रेषक प्रक्रिया में भेजने के लिए कॉल तक पहुंचने के लिए पर्याप्त समय नहीं हो सकता है और इसलिए आपका handler.Available 0 है और रिटर्न प्राप्त होता है।

यही कारण है कि जब आप 500 एमएस की नींद जोड़ते हैं तो "बग" नहीं होता है।

+0

आप सही हैं, लेकिन 7 मिनट देर से;) – Lucero

+0

मुझे लगता है कि मैंने 500 एमएस को ठीक करने का कारण भी जोड़ा है। मैंने आपके उत्तर की प्रतिलिपि नहीं बनाई ... – Tudor

+0

क्षमा करें, मेरा इरादा आपके उत्तर को ऐसा करने के लिए नहीं था जैसा कि यह मेरी ओर से कॉपी किया गया था। फिर भी, वे अनिवार्य रूप से वही कहते हैं - मेरा "पूरी शुरुआत ..." वाक्य के साथ देरी के साथ अलग-अलग व्यवहार को स्पष्ट रूप से संबोधित करता है। ;) – Lucero

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