2015-09-10 20 views
9

के बाद मेरे पास दो भाग, ग्राहक और सर्वर हैं। और मैं क्लाइंट से सर्वर पर डेटा (आकार> 5840 बाइट्स) भेजने की कोशिश करता हूं और फिर सर्वर डेटा वापस भेजता है। मैं इसे हर बार एक दूसरे के बीच एक सेकंड इंतजार लूप। कुछ समय सर्वर अनुप्रयोग क्रैश, दुर्घटना बहुत यादृच्छिक लगता है त्रुटि:यादृच्छिक "रिमोट होस्ट द्वारा एक मौजूदा कनेक्शन जबरन बंद कर दिया गया था।" एक टीसीपी रीसेट

Unhandled Exception: System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. --->

System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host

at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 s ize)

--- End of inner exception stack trace ---

at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 s ize)

at TCP_Server.Program.Main(String[] args)

क्लाइंट कोड (यह पाश अंदर है):

  try 
      { 
       Int32 port = 13777; 
       using (TcpClient client = new TcpClient(ip, port)) 
       using (NetworkStream stream = client.GetStream()) 
       { 
        client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); 
        var data = GenerateData(size); 

        sw.Start(); 
        // Send the message to the connected TcpServer. 
        stream.Write(data, 0, data.Length); 

        // Buffer to store the response bytes. 
        data = new Byte[size]; 

        // Read the first batch of the TcpServer response bytes. 
        Int32 bytes = stream.Read(data, 0, data.Length); 

        sw.Stop(); 
        Console.WriteLine(i + ": Done transporting " + size + " bytes to and from " + ip + " time: " + 
             sw.ElapsedMilliseconds + " ms"); 
        // Close everything. 
        stream.Close(); 
        client.Close(); 
       } 

      } 
      catch (ArgumentNullException e) 
      { 
       Console.WriteLine("ArgumentNullException: {0}", e); 
      } 
      catch (SocketException e) 
      { 
       Console.WriteLine("SocketException: {0}", e); 
      } 

      sw.Reset(); 

सर्वर कोड:

  Byte[] bytes = new Byte[size]; 

      // Enter the listening loop. 
      for (int i = 0; i < numberOfPackages; i++) 
      { 
       using (TcpClient client = server.AcceptTcpClient()) 
       using (NetworkStream stream = client.GetStream()) 
       { 
        client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); 
        // Loop to receive all the data sent by the client. 
        while ((stream.Read(bytes, 0, bytes.Length)) != 0) 
        { 
         // Send back a response. 
         stream.Write(bytes, 0, size); 

        } 
        client.GetStream().Close(); 
        client.Close(); 
       } 


       Console.WriteLine("Receive data size " + size); 

      } 

मेरे पास है भेजे गए tcp संकुलों की निगरानी करने के लिए wireshark का उपयोग किया गया और पाया कि प्रोग्राम क्रैश होने से पहले एक टीसीपी आरएसटी क्लाइंट से सर्वर पर भेजा जाता है। तो मुझे लगता है कि समस्या यह है कि आरएसटी सही ढंग से संभाल नहीं है। क्लाइंट और होस्ट के बीच कोई फ़ायरवॉल नहीं है, इसलिए समस्या नहीं है। तो या तो मैं टीसीपी आरएसटी से छुटकारा पाने की जरूरत है या मैं अपने सर्वर की जरूरत है किसी तरह से इसे संभाल करने के लिए और क्रैश नहीं https://www.dropbox.com/sh/ctl2chq3y2c20n7/AACgIJ8IRiclqnyOyw8sqd9La?dl=0

:

दोनों क्लाइंट और सर्वर के लिए wireshark फ़ाइलें यहाँ है।

मैंने लंबे समय तक प्रतीक्षा करने का प्रयास किया है लेकिन इससे मदद नहीं मिलती है। यदि डेटा 5840 बाइट्स से नीचे है तो मुझे कोई क्रैश नहीं मिलता है, जो मुझे पता है।

कोई सुझाव या विचार?

संपादित करें: जवाब मैं इसे निम्नलिखित परिवर्तनों के साथ काम मिल गया के लिए धन्यवाद:

सर्वर:

// Loop to receive all the data sent by the client. 
int k = 0; 
while (k < size) 
{ 
    int bytesRead = stream.Read(bytes, 0, bytes.Length); 
    k += bytesRead; 
} 
// Send back a response. 
stream.Write(bytes, 0, size); 

और एक ही जब क्लाइंट की तरफ मत प्राप्त हुए। चूंकि मैं पहले सभी डेटा भेजना चाहता हूं और फिर सर्वर को मेरे आवेदन के लिए इस काम का जवाब देना चाहिए।

उत्तर

7

दो समस्याओं कि मैं देख रहा हूँ:

  1. आप मानते हैं कि size बाइट्स के लिए पठन वास्तव में size बाइट्स पढ़ा जाएगा। ऐसा नहीं होता। टीसीपी एक स्ट्रीमिंग प्रोटोकॉल है। एक पढ़ा कम से कम एक बाइट पढ़ता है। यही एकमात्र गारंटी है।
  2. आपका कोड यादृच्छिक रूप से डेडलॉक होगा। ग्राहक सर्वर को डेटा लिखता है। सर्वर इसे वापस echos। लेकिन क्लाइंट तब तक नहीं पढ़ेगा जब तक कि उसने सबकुछ लिखा न हो। यदि यह नेटवर्क बफर से अधिक लिखता है तो यह डेडलॉक ले सकता है। ग्राहक को समवर्ती रूप से पढ़ना और लिखना चाहिए। शायद, आपको डेटा को वापस पढ़ने के लिए एक और धागा/कार्य की आवश्यकता है। उस मुद्दे को हल करने के लिए एक अच्छा पैटर्न एक लेखक कार्य, एक पाठक कार्य और कार्य शुरू करना होगा। जब सभी/प्रतीक्षा करें उन्हें वापस शामिल करने के लिए।

मुझे यकीन नहीं है कि टीसीपी स्टैक एक सटीक परिस्थितियों में एक आरएसटी भेज देगा। एक टाइमआउट के कारण डेडलॉक के कारण हो सकता है।

आप किसी भी अपवाद को निगल नहीं रहे हैं, है ना?

आम तौर पर, कनेक्शन बंद करना पृष्ठभूमि में व्यवस्थित शट डाउन करता है। लेकिन मुझे इस बात पर अनिश्चितता है कि क्या होता है जब दूसरी तरफ इस बिंदु पर अभी भी लिख रहा है। शायद जवाब यह है कि एक आरएसटी लिखने के प्राप्तकर्ता द्वारा उत्पन्न होता है। निश्चित रूप से, टीसीपी स्पेक इस सवाल का जवाब देगा। यदि this answer पर भरोसा किया जाना है तो वास्तव में एक शटडाउन (पढ़ें)/बंद आने वाले लिखने के बाद कनेक्शन आरएसटी होगा।

दोनों मुद्दों को ठीक करें और अपने निष्कर्षों के साथ रिपोर्ट करें।

+0

धन्यवाद !!! चूंकि मुझे केवल भेजने के लिए मेरे आवेदन की आवश्यकता है और फिर एक ही समय में यह प्राप्त नहीं होता है, मुझे केवल पहली समस्या को ठीक करने की आवश्यकता होती है। – TobiasW

+0

@TobiasW मुझे लगता है कि आप डेडलॉक समस्या को समझ नहीं पाए। यह कोड यादृच्छिक रूप से डेडलॉक होगा। 100 एमबी भेजने का प्रयास करें और यह निश्चित रूप से डेडलॉक होगा। – usr

+0

भले ही मैं पहले क्लाइंट से सबकुछ भेजूं, फिर भी सर्वर इसे वापस भेजने से पहले सबकुछ प्राप्त करता है? इसके बाद मैं इंतजार करता हूं और सबकुछ फिर से करता हूं। कोड का उपयोग वास्तविक रूप से नहीं किया जाता है, यह बेंचमार्क एप्लिकेशन से अधिक है। – TobiasW

0

मैं कोई विशेषज्ञ हूँ, लेकिन आप क्लाइंट पर stream.Close() कॉल नहीं लगता कि धारा बंद हो जाएगा, जबकि सर्वर अभी भी

// Send back a response. 
stream.Write(bytes, 0, size); 

पर लिखने की कोशिश कर रहा है इसके अलावा, आप चिह्नित करने के लिए कुछ डेटा डाल करने के लिए चाहते हो सकता है इसका अंत, ताकि सर्वर जानता है और पढ़ना बंद कर देता है।

+0

हो सकता है, क्या आपको पता है कि क्या बदलना है? मैं अब 2 दिनों के लिए इस समस्या से फंस गया हूं इसलिए मैं वास्तव में थक गया हूं। – TobiasW

+0

या तो कुछ शीर्षलेख भेजें जिसमें डेटा की लंबाई हो या इसके अंत में चिह्नित करने के लिए डेटा के लिए कुछ अद्वितीय अनुक्रम संलग्न हो। सर्वर प्रक्रिया में यह जानने के लिए कि सर्वर कब पढ़ना समाप्त होता है। अन्य उत्तर में usr द्वारा सुझाव भी लागू करें। या बस पहले एक ही तरीके से स्थानांतरण पर काम करें, ताकि आप समस्या को इंगित कर सकें। – user2527768

+0

और जटिलताओं से बचने के लिए, यदि आप अपने लिए ऐसा करने योग्य हैं, तो आप विभिन्न बंदरगाहों को पढ़ और लिख सकते हैं। – user2527768

0

मैंने आईआईएस रूट एंट्री की बढ़ती कैश सीमा के साथ एक ही समस्या हल की। आप कैशिंग अक्षम भी कर सकते हैं। आशा करता हूँ की ये काम करेगा।

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

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