2011-02-07 10 views
17

मेरे पास boost::asio अतुल्यकालिक रूप से उपयोग कर क्लाइंट और सर्वर है। मैं कनेक्शन बंद करने के लिए कुछ टाइमआउट जोड़ना चाहता हूं और कुछ गलत होने पर संभावित रूप से पुनः प्रयास करना चाहता हूं।कोई बढ़ावा दें :: asio async स्वचालित रूप से समय निकालता है?

मेरा प्रारंभिक विचार यह था कि जब भी मैं async_ फ़ंक्शन पर कॉल करता हूं तो मुझे एसिंक ऑपरेशन को पूरा होने के बाद समाप्त होने के लिए deadline_timer भी समाप्त करना चाहिए। अब मैं सोच रहा हूं कि क्या हर मामले में यह सख्ती से जरूरी है।

उदाहरण के लिए:

  • async_resolve संभवतः सिस्टम के समाधानकर्ता जो इसे में बनाया गया समय समाप्ति हो (उदा resolv.h में RES_TIMEOUT संभवतः /etc/resolv.conf में विन्यास द्वारा ओवरराइड) का उपयोग करता है। अपना खुद का टाइमर जोड़कर, मैं इस बात से संघर्ष कर सकता हूं कि उपयोगकर्ता अपने रिज़ॉल्वर को कैसे काम करना चाहता है।

  • async_connect के लिए, connect(2) syscall में बनाया टाइमआउट किसी प्रकार का है यह

  • आदि

तो जो (यदि हो तो) async_ कॉल के अंतर्गत उनके संचालकों कॉल करने के लिए गारंटी दी जाती है एक " उचित "समय सीमा? और यदि कोई ऑपरेशन [कर सकता है] टाइमआउट होगा हैंडलर basic_errors::timed_out त्रुटि या कुछ और पारित किया जाएगा?

+0

मुझे अपनी खुद की 'deadline_timer' बनाने के लिए भी चिपकना पड़ा, इसलिए मुझे यह देखने में बहुत दिलचस्पी होगी कि यह अनावश्यक है या नहीं। – chrisaycock

+0

+1 दिलचस्प सवाल है। मुझे लगता है कि जवाब काफी हद तक मंच निर्भर होगा। मुझे लगता है कि आप लिनक्स के बारे में परवाह करते हैं? –

उत्तर

29

तो मैंने कुछ परीक्षण किया। मेरे परिणामों के आधार पर, यह स्पष्ट है कि वे अंतर्निहित ओएस कार्यान्वयन पर निर्भर करते हैं। संदर्भ के लिए, मैंने इसे स्टॉक फेडोरा कर्नेल के साथ परीक्षण किया: 2.6.35.10-74.fc14.x86_64

लब्बोलुआब यह है कि async_resolve() केवल इस मामले में जहां आप एक deadline_timer की स्थापना के बिना दूर प्राप्त करने में सक्षम हो सकता है होना करने के लिए लग रहा है है। यह उचित व्यवहार के लिए हर दूसरे मामले में व्यावहारिक रूप से आवश्यक है।


async_resolve()

async_resolve() को एक कॉल 5 सेकंड के अलावा 4 प्रश्नों में हुई। boost::asio::error::host_not_found त्रुटि के अनुरोध के बाद हैंडलर को 20 सेकंड कहा गया था।

2 प्रयत्न (resolv.h) के साथ 5 सेकंड के एक समय समाप्ति मेरे समाधानकर्ता चूक है, तो ऐसा लगता है के लिए कॉन्फ़िगर प्रश्नों के दो बार संख्या भेजने के लिए। व्यवहार options timeout और options attempts/etc/resolv.conf में सेट करके संशोधित है। प्रत्येक मामले में भेजे गए प्रश्नों की संख्या दोगुनी थी जो attempts को सेट किया गया था और हैंडलर को बाद में host_not_found त्रुटि के साथ बुलाया गया था।

परीक्षण के लिए, एकल कॉन्फ़िगर किया गया नेमसर्वर ब्लैक-होल रूट किया गया था।


async_connect()

एक ब्लैक होल से कराई गंतव्य के साथ async_connect() कॉलिंग हैंडलर ~ 189 सेकंड के बाद त्रुटि boost::asio::error::timed_out साथ बुलाया जा रहा है के परिणामस्वरूप।

ढेर ने प्रारंभिक SYN और 5 रीट्री भेजीं। पहली बार पुनः प्रयास 3 सेकंड के बाद भेजा गया था, प्रत्येक बार दोबारा रेट्री टाइमआउट (3 + 6 + 12 + 24 + 48 + 96 = 18 9)। पुनर्प्रयास की संख्या बदला जा सकता है:

% sysctl net.ipv4.tcp_syn_retries 
net.ipv4.tcp_syn_retries = 5 

5 के डिफ़ॉल्ट RFC 1122 (4.2.3.5) के साथ पालन करने के लिए चुना जाता है: एक SYN खंड के लिए

[पुनर्संचरण टाइमर] होना चाहिए पर पर्याप्त रूप से सेट करें, कम से कम 3 मिनट के लिए सेगमेंट के पुन: ट्रांसमिशन प्रदान करें। एप्लिकेशन कनेक्शन (यानी, खुले प्रयास पर छोड़ दें) जल्द से जल्द बंद कर सकता है।

3 मिनट = 180 सेकंड, हालांकि आरएफसी ऊपरी बाउंड निर्दिष्ट नहीं करता है। हमेशा के लिए पुनः प्रयास करने से कार्यान्वयन रोकने के लिए कुछ भी नहीं है।


async_write()

जब तक सॉकेट के भेजने बफर पूर्ण नहीं था, इस हैंडलर हमेशा उसी समय कहा जाता था।

मेरी परीक्षा ने एक टीसीपी कनेक्शन स्थापित किया और एक मिनट बाद async_write() पर कॉल करने के लिए टाइमर सेट किया। मिनट जहां कनेक्शन स्थापित किया गया था लेकिन async_write() कॉल करने से पहले के दौरान, मैं हाथापाई के सभी प्रकार की कोशिश की:

  • गंतव्य के लिए ब्लैक होल बाद यातायात के लिए एक नीचे की ओर रूटर की स्थापना।
  • सत्र को डाउनस्ट्रीम फ़ायरवॉल में साफ़ करना ताकि यह गंतव्य से खराब आरएसटी के साथ जवाब दे सके।
  • मेरी ईथरनेट
  • /etc/init.d/network stop

चल रहा है कोई फर्क नहीं पड़ता कि मैं क्या किया अनप्लग, अगले async_write() तुरंत सफलता रिपोर्ट करने के लिए अपने हैंडलर कॉल करेगा।

मामले में जहां फ़ायरवॉल जाली आरएसटी में, कनेक्शन तुरंत बंद हो गया है, लेकिन मैं जानने का कोई तरीका था कि जब तक मैं अगले आपरेशन का प्रयास किया है (जो तुरंत boost::asio::error::connection_reset रिपोर्ट करेंगे)। अन्य मामलों में, कनेक्शन खुला रहेगा और जब तक यह अंततः 17-18 मिनट बाद समाप्त नहीं हो जाता तब तक त्रुटियों की रिपोर्ट न करें।

async_write() के लिए सबसे खराब मामला यह है कि यदि मेजबान पुन: प्रेषण कर रहा है और प्रेषण बफर भरा हुआ है।यदि बफर भरा हुआ है, तो async_write() रीट्रांसमिशन समय समाप्त होने तक अपने हैंडलर को कॉल नहीं करेगा। 15 पुनर्संचरण को लिनक्स चूक:

% sysctl net.ipv4.tcp_retries2 
net.ipv4.tcp_retries2 = 15 

समय पुनर्संचरण के बीच (जैसे विशिष्ट कनेक्शन की अनुमानित राउंड ट्रिप समय के रूप में और कई कारकों पर आधारित है) प्रत्येक के बाद बढ़ जाती है लेकिन 2 मिनट में जोड़ा जाता है। तो डिफ़ॉल्ट 15 रीट्रांसमिशन और सबसे खराब-केस 2-मिनट का टाइमआउट के साथ, async_write() हैंडलर के लिए ऊपरी बाउंड 30 मिनट है। जब इसे कहा जाता है, तो त्रुटि boost::asio::error::timed_out पर सेट की जाती है।


async_read()

यह जब तक कनेक्शन स्थापित हो जाने और कोई डेटा प्राप्त होता है अपने हैंडलर फोन कभी नहीं करना चाहिए। मेरे पास इसका परीक्षण करने का समय नहीं है।

+2

यह एक उत्तर होना चाहिए ... मेरा संक्षिप्त उत्तर क्या था उससे ज्यादा रिलीज विवरण देता है। – diverscuba23

10

उन दो कॉलों में आपके हैंडलर तक पहुंचने वाले टाइमआउट हैं, लेकिन आप उन समयों में से किसी एक समय से पहले की अवधि में आश्चर्यचकित हो सकते हैं। (मुझे पता है कि मैंने कनेक्शन को बसने दिया है और प्रक्रिया को मारने से पहले boost::asio के साथ 10 मिनट से अधिक के लिए एकल कनेक्ट कॉल पर कनेक्ट करने का प्रयास किया है)। इसके अलावा async_read और async_write कॉलों में उनके साथ जुड़े टाइमआउट नहीं हैं, इसलिए यदि आप अपने पढ़ने और लिखने पर टाइमआउट करना चाहते हैं, तो आपको अभी भी deadline_timer की आवश्यकता होगी।

+1

+1 जब संदेह में, स्पष्ट हो। यदि व्यवहार दस्तावेज नहीं है तो अपने स्वयं के टाइमर जोड़ें। –

+0

हाँ। यह मुझे बहुत कुछ मिला है। यद्यपि 'async_read' और' async_write' * * के पास इस अर्थ में टाइमआउट हैं कि अत्यधिक पुन: ट्रांसमिशन अंततः कनेक्शन को दस मिनट के बाद बंद कर देगा। – eater

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