2010-01-02 13 views
22

साफ़ रूप से डिस्कनेक्ट कर रहा है कभी-कभी बूस्ट :: एएसओ इसे पहले से डिस्कनेक्ट करने से पहले डिस्कनेक्ट लगता है, यानी सर्वर से डिस्कनेक्ट को ठीक से संभालता है। मुझे यकीन नहीं है कि यह कैसे संभव है क्योंकि क्लाइंट को लगता है कि यह पूरी तरह से संदेश भेजता है, फिर भी जब सर्वर त्रुटि को उत्सर्जित करता है तो यह संदेश हेडर भी नहीं पढ़ता है ... परीक्षण के दौरान केवल 5 बार में 1 होता है, सर्वर क्लाइंट को बंद संदेश प्राप्त करता है, और क्लाइंट को स्पष्ट रूप से डिस्कनेक्ट करता है।बूस्ट :: एएसआईओ

त्रुटि:

ग्राहक डिस्कनेक्ट करने "एक मौजूदा कनेक्शन बलपूर्वक दूरस्थ होस्ट द्वारा बंद कर दिया गया था":

void disconnect() 
{ 
    boost::system::error_code error; 
    //just creates a simple buffer with a shutdown header 
    boost::uint8_t *packet = createPacket(PC_SHUTDOWN,0); 
    //sends it 
    if(!sendBlocking(socket,packet,&error)) 
    { 
     //didnt get here in my tests, so its not that the write failed... 
     logWrite(LOG_ERROR,"server", 
      std::string("Error sending shutdown message.\n") 
      + boost::system::system_error(error).what()); 
    } 

    //actaully disconnect 
    socket.close(); 
    ioService.stop(); 
} 
bool sendBlocking(boost::asio::ip::tcp::socket &socket, 
    boost::uint8_t *data, boost::system::error_code* error) 
{ 
    //get the length section from the message 
    boost::uint16_t len = *(boost::uint16_t*)(data - 3); 
    //send it 
    asio::write(socket, asio::buffer(data-3,len+3), 
     asio::transfer_all(), *error); 
    deletePacket(data); 
    return !(*error); 
} 

सर्वर:

void Client::clientShutdown() 
{ 
    //not getting here in problem cases 
    disconnect(); 
} 
void Client::packetHandler(boost::uint8_t type, boost::uint8_t *data, 
    boost::uint16_t len, const boost::system::error_code& error) 
{ 
    if(error) 
    { 
     //error handled here 
     delete[] data; 
     std::stringstream ss; 
     ss << "Error recieving packet.\n"; 
     ss << logInfo() << "\n"; 
     ss << "Error: " << boost::system::system_error(error).what(); 
     logWrite(LOG_ERROR,"Client",ss.str()); 

     disconnect(); 
    } 
    else 
    { 
     //call handlers based on type, most will then call startRead when 
     //done to get the next packet. Note however, that clientShutdown 
     //does not 
     ... 
    } 
} 



void startRead(boost::asio::ip::tcp::socket &socket, PacketHandler handler) 
{ 
    boost::uint8_t *header = new boost::uint8_t[3]; 
    boost::asio::async_read(socket,boost::asio::buffer(header,3), 
     boost::bind(&handleReadHeader,&socket,handler,header, 
     boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error)); 
} 
void handleReadHeader(boost::asio::ip::tcp::socket *socket, PacketHandler handler, 
    boost::uint8_t *header, size_t len, const boost::system::error_code& error) 
{ 
    if(error) 
    { 
     //error "thrown" here, len always = 0 in problem cases... 
     delete[] header; 
     handler(0,0,0,error); 
    } 
    else 
    { 
     assert(len == 3); 
     boost::uint16_t payLoadLen = *((boost::uint16_t*)(header + 0)); 
     boost::uint8_t type  = *((boost::uint8_t*) (header + 2)); 
     delete[] header; 
     boost::uint8_t *payLoad = new boost::uint8_t[payLoadLen]; 

     boost::asio::async_read(*socket,boost::asio::buffer(payLoad,payLoadLen), 
      boost::bind(&handleReadBody,socket,handler, 
      type,payLoad,payLoadLen, 
      boost::asio::placeholders::bytes_transferred,boost::asio::placeholders::error)); 
    } 
} 
void handleReadBody(ip::tcp::socket *socket, PacketHandler handler, 
    boost::uint8_t type, boost::uint8_t *payLoad, boost::uint16_t len, 
    size_t readLen, const boost::system::error_code& error) 
{ 
    if(error) 
    { 
     delete[] payLoad; 
     handler(0,0,0,error); 
    } 
    else 
    { 
     assert(len == readLen); 
     handler(type,payLoad,len,error); 
     //delete[] payLoad; 
    } 
} 
+0

क्या आपको कभी इसका जवाब मिला? – GrahamS

उत्तर

21

मुझे लगता है कि socket.close() पर कॉल करने से पहले आपको शायद socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec) पर कॉल करना चाहिए।

boost::asio documentation for basic_stream_socket::close कहता है:

For portable behaviour with respect to graceful closure of a connected socket, call shutdown() before closing the socket.

यह सुनिश्चित करना चाहिए कि सॉकेट पर किसी भी लंबित ऑपरेशन ठीक से रद्द कर रहे हैं और किसी भी प्रतिरोधक कॉल socket.close करने से पहले प्लावित कर रहे हैं।

+0

मेरे पास फायर लांसर के समान ही समस्या थी, और यह मेरे लिए धन्यवाद, धन्यवाद। यह शायद स्वीकार्य उत्तर होना चाहिए। – Silverlan

5

हो सकता है कि यह क्या हो रहा है है :

  • ग्राहक भेज डिस्कनेक्ट पैकेट
  • ग्राहक नीचे
  • सर्वर पढ़ हैंडलर कहा जाता हो जाता है बन्द हो जाता है सॉकेट, लेकिन वहाँ क्योंकि सॉकेट पहले से ही बंद कर दिया है बंद पैकेट के साथ जुड़े एक त्रुटि है।

यदि कोई त्रुटि है, तो मैं आपके पढ़ने वाले हैंडलर में देखता हूं, आप यह देखने के लिए कभी भी जांच नहीं करते कि आपका शट डाउन पैकेट है या नहीं। एसा हो सकता हे। असल में जो मैं कह रहा हूं वह शायद आपके क्लाइंट को अलग-अलग प्रक्रिया करने का मौका मिलने से पहले कभी-कभी क्लोज़ और शटडाउन पैकेट दोनों को भेजने में सक्षम होता है।

+0

"// त्रुटि" फेंक दी गई ", समस्या मामलों में हमेशा len = 0 ..." तो यह हमेशा हेडर के 0 बाइट्स पढ़ता है, यानी उसने किसी भी पैकेट को नहीं पढ़ा है ... और नींद चिपकाना (500) या क्लाइंट पर कुछ अच्छा समाधान नहीं है, क्योंकि यह अभी भी धीमे नेटवर्क पर पर्याप्त नहीं हो सकता है और यह एक उल्लेखनीय देरी है। –

+0

शायद सर्वर से एक ठीक पैकेज के लिए प्रतीक्षा करें, या सर्वर के बजाय डिस्कनेक्ट है? – Macke

+0

लेकिन यदि क्लाइंट सर्वर को डिस्कनेक्ट संदेश भेजने के लिए इंतजार कर रहा है (क्लाइंट डिस्कनेक्ट संदेश के जवाब में), तो मैं क्लाइंट पर डिस्कनेक्ट करने वाले सर्वर की विपरीत समस्या के साथ समाप्त हो जाऊंगा .... –

3

async_write() का उपयोग करें और लिखने वाले हैंडलर के अंदर socket.close() डालें। यह सुनिश्चित करेगा कि पैकेट को एएसओ द्वारा संसाधित किया जाता है और प्रसंस्करण के बीच में उपेक्षित नहीं किया जाता है (करीबी() कॉल के कारण)।

2

मेरे पास एक बहुत ही समान समस्या है। मेरा मानना ​​है कि यह विंडोज रीसाइक्लिंग कनेक्शन से संबंधित है। क्या निम्नलिखित परिचित है?

  • आपको प्रोग्राम शुरू करने के तुरंत बाद यह त्रुटि मिलती है लेकिन कनेक्शन स्थापित होने के बाद नहीं?
  • यदि आप अपने एप्लिकेशन को पुनरारंभ करने से पहले 4 मिनट से अधिक समय तक प्रतीक्षा करते हैं तो त्रुटि कभी नहीं होती है?

टीसीपी चश्मा निर्दिष्ट करते हैं कि डिफ़ॉल्ट रूप से इसे टीसीपी कनेक्शन बंद होने पर अंतिम स्वीकृति के लिए चार मिनट का इंतजार करना चाहिए। आप netstat का उपयोग कर इन कनेक्शन को FIN_WAIT स्थिति में देख सकते हैं। जब आप सटीक उसी सिस्टम से कनेक्ट करने का प्रयास करते हैं और इन आंशिक रूप से बंद कनेक्शन लेते हैं और उन्हें रीसायकल करते हैं तो विंडोज ओएस पता लगाता है। कार्यक्रम के आपके दूसरे आमंत्रण को पहले बंद से 'बंद' कनेक्शन पीछे छोड़ दिया जाता है। यह अगली स्वीकृति प्राप्त करता है और फिर वास्तव में बंद हो जाता है।

9

मैं दोनों करीब() विधि और शट डाउन() विधि

socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec) 

बंद विधि दो का सबसे अच्छा है के साथ ऐसा करने की कोशिश की है। हालांकि, मुझे लगता है कि एएसआईओ सॉकेट के विनाशक का उपयोग करने का यह साफ तरीका है क्योंकि एएसआईओ आपके लिए यह सब ख्याल रखता है। तो आपका लक्ष्य है कि सॉकेट को दायरे से बाहर निकलने दें। अब, आप इसे आसानी से साझा_ptr का उपयोग करके और साझा_प्टर को ताजा सॉकेट या शून्य पर रीसेट कर सकते हैं। यह एएसआईओ सॉकेट के विनाशक को बुलाएगा और जीवन अच्छा है।

+0

'shared_ptr' का उपयोग करना बहुत अच्छा काम करता है! – nabroyan

+0

यह भ्रामक है। विनाशक केवल socket.close (ec) द्वारा कार्य करता है, https://stackoverflow.com/a/39823756/1889040 देखें। तो आपको ठीक से बंद करने के लिए 'socket.shutdown' मैन्युअल रूप से कॉल करना होगा। मैं पुष्टि कर सकता हूं कि 'socket.shutdown' बफर के बिना (बंद होने की कॉल से पहले) फ़्लश नहीं किया जा सकता है। – scinart

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