2009-09-11 25 views
6

मैं कुछ कोड में कई "अल्पकालिक" सॉकेट कि कि तरह लग रहे बनाने के लिए:क्या सॉकेट को फिर से खोलने का कोई तरीका है?

nb=1000 
for i in range(nb): 
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sck.connect((adr, prt) 
    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
    sck.close() 

यह ठीक काम करता है, जब तक कि nb "छोटे" है पर्याप्त।

रूप nb काफी बड़ी है, हालांकि हो सकता है, मैं इस

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.connect((adr, prt) 
for i in range(nb): 
    reopen(sck) # ? ? ? 
    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
sck.close() 

की तरह कुछ करना चाहते हैं तो सवाल यह है:
वहाँ किसी भी तरह से एक सॉकेट कि कर दिया गया है "का पुन: उपयोग करने के लिए" है बंद करना ?

उत्तर

15

नहीं, यह अंतर्निहित सी सॉकेट (और उस मामले के लिए टीसीपी/आईपी प्रोटोकॉल) की सीमा है। मेरा सवाल यह है कि: जब आप अपने आवेदन को आर्किटेक्ट करने के लिए आर्किटेक्ट कर सकते हैं तो आप उन्हें क्यों बंद कर रहे हैं?

कई शॉर्ट-टर्म सॉकेट के साथ समस्या यह है कि उन्हें बंद करने से उन्हें एक ऐसे राज्य में रखा जाता है जहां उन्हें थोड़ी देर के लिए उपयोग नहीं किया जा सकता है (मूल रूप से, दो बार पैकेट जीवनकाल, यह सुनिश्चित करने के लिए कि नेटवर्क में किसी भी पैकेट आते हैं और छोड़ दिए जाते हैं , या नेटवर्क से खुद को छोड़ दिया)। असल में क्या होता है कि, 4-टुपल में अद्वितीय होने की आवश्यकता होती है (स्रोत आईपी, स्रोत पोर्ट, गंतव्य आईपी, गंतव्य पोर्ट), पहला और आखिरी दो हमेशा एक जैसा होता है, जब आप स्रोत से बाहर निकलते हैं बंदरगाहों, आप होस कर रहे हैं।

हमने इस समस्या को सॉफ़्टवेयर में मारा है इससे पहले कि जब हम तेजी से मशीनों पर दौड़ते थे तो यह केवल स्पष्ट हो गया था (क्योंकि हम कई और सत्रों का उपयोग कर सकते थे)।

क्यों आप सिर्फ सॉकेट खोलते हैं और इसका उपयोग जारी रखते हैं? ऐसा लगता है कि आपका प्रोटोकॉल एक साधारण अनुरोध/प्रतिक्रिया एक है, जिसे उस दृष्टिकोण के साथ आसानी से सक्षम किया जाना चाहिए।

कुछ की तरह:

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.connect((adr, prt) 
for i in range(nb): 
    sck.send('question %i'%i) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
sck.close() 

अद्यतन:

एक संभावना यह (और हम किया है इस से पहले) यदि आप इस नित्य खुला होने के कारण कनेक्शन से बाहर चला रहे हैं/बंद, है समस्या का पता लगाने और इसे थ्रॉटल करने के लिए। निम्नलिखित कोड पर विचार करें (सामान मैं जोड़ दिया है के बाद से मैं काफी कुछ समय के लिए अजगर छुआ है अजगर की तुलना में अधिक छद्म कोड है):

for i in range(nb): 
    sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
    sck.connect((adr, prt) 

    while sck.error() == NO_SOCKETS_AVAIL: 
     sleep 250 milliseconds 
     sck.connect((adr, prt) 

    sck.send('question %i'%i) 
    sck.shutdown(SHUT_WR) 
    answer=sck.recv(4096) 
    print 'answer %i : %s' % (%i, answer) 
    sck.close() 

असल में, यह आप पूरी रफ्तार से चलाने के देखते हैं, जबकि सुविधा देता है बहुत सारे संसाधन लेकिन जब आप अपनी समस्या क्षेत्र पर हमला करते हैं तो धीमा हो जाता है। वास्तव में संसाधनों के कम होने पर असफल होने की समस्या को "ठीक करने" के लिए हमने अपने उत्पाद के साथ क्या किया है। हम इस तथ्य को छोड़कर फिर से वास्तुकार कर चुके थे कि यह जीवन के अंत में एक विरासत उत्पाद था और हम मूल रूप से सेवा के लिए निश्चित-लागत-लागत मोड में थे।

+0

मेरी इच्छा है कि मैं ऐसा कर सकूं, लेकिन दुर्भाग्यवश मुझे सॉकेट को बंद करना होगा (या कम से कम "आधे बंद करें") अन्यथा कॉल कॉल ब्लॉक भेजें और मुझे कभी जवाब नहीं मिलेगा। मुझे लगता है कि अगर मैं सॉकेट को बंद नहीं करता हूं, तो सर्वर नहीं जानता कि मैं डेटा भेज रहा हूं और कुछ और इंतजार कर रहा हूं। – dugres

+0

डेटा स्ट्रीम में डिलीमीटरों (उदाहरण के लिए) के आधार पर आपको अधिक "समझदार" दृष्टिकोण का उपयोग करने के लिए सर्वर को फिर से लिखना होगा। लेकिन एक और संभावना है - समस्या को हल करने के लिए हमने जो दृष्टिकोण लिया है, उसके लिए मेरा अपडेट देखें। – paxdiablo

+0

@ पैक्स: मैंने आपका समाधान लागू किया है और यह किसी भी "एनबी" के लिए बहुत अच्छा काम करता है। आपका बहुत बहुत धन्यवाद। – dugres

1

यदि आप एक ही बंदरगाह के लिए खोलने और बंद करने वाले सॉकेट रखते हैं तो यह सॉकेट खोलने और इसे खोलने के लिए बेहतर है, तो आपके पास बेहतर प्रदर्शन होगा, क्योंकि खोलने और बंद होने में कुछ समय लगेगा।

यदि आपके पास कई शॉर्ट-टर्म सॉकेट हैं, तो आप डेटाग्राम सॉकेट (यूडीपी) पर भी विचार कर सकते हैं। ध्यान दें कि आपके पास इस मामले में आगमन की गारंटी नहीं है, पैकेट के आदेश की भी गारंटी नहीं है।

3

मुझे यकीन नहीं है कि अतिरिक्त ओवरहेड कैसा होगा, लेकिन आप सॉकेट को पूरी तरह बंद कर सकते हैं और फिर से खोल सकते हैं।आपको SO_REUSEADDR सेट करने की आवश्यकता है, और एक विशिष्ट पोर्ट से बांधें जिसे आप पुन: उपयोग कर सकते हैं।

sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
+0

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

0

आप सॉकेट का पुन: उपयोग नहीं कर सकते हैं लेकिन यह अगर तुम सकता है मदद नहीं करेंगे, क्योंकि आप बंदरगाहों, नहीं सॉकेट से बाहर चल रहे हैं। शट डाउन शुरू करने के बाद प्रत्येक पोर्ट अधिकतम सेगमेंट लाइफटाइम के लिए TIME_WAIT state में रहेगा। इतनी छोटी अवधि के भीतर इतने सारे बंदरगाहों की आवश्यकता नहीं है, लेकिन यदि आपको बड़ी संख्या का उपयोग करने की आवश्यकता है तो आप ephemeral port range को बढ़ा सकते हैं।

पोर्ट नंबर 16 बिट हैं और इसलिए उनमें से केवल 65536 हैं। यदि आप विंडोज या मैक ओएस एक्स पर हैं तो डिफ़ॉल्ट रूप से, तात्कालिक बंदरगाहों को 49152 से 65535 तक चुना जाता है। यह official range designated by IANA है, लेकिन लिनक्स और सोलारिस (अक्सर उच्च ट्रैफिक सर्वर के लिए उपयोग किया जाता है) पर डिफ़ॉल्ट सीमा 32768 पर शुरू होती है अधिक बंदरगाहों के लिए। यदि आप पहले से ही इस तरह से सेट नहीं हैं और आपको अधिक तात्कालिक बंदरगाहों की आवश्यकता है तो आप अपने सिस्टम में एक समान परिवर्तन करना चाहेंगे।

यह भी अपने सिस्टम पर अधिकतम खंड जीवन को कम करने, समय है कि प्रत्येक सॉकेट TIME_WAIT राज्य में है, या कुछ मामलों में SO_REUSEADDR या SO_LINGER उपयोग करने के लिए बंदरगाहों पुन: उपयोग करने से पहले समय समाप्त हो गया है की मात्रा को कम संभव है। हालांकि यह कम से कम सैद्धांतिक रूप से पुराने कनेक्शन को नए कनेक्शन के साथ मिश्रित करने का कारण बन सकता है जो कि उसी पोर्ट नंबर का उपयोग करने के लिए होता है, यदि पुराने कनेक्शन से कुछ पैकेट आने में धीमे होते हैं, तो आम तौर पर यह एक अच्छा विचार नहीं है।

+0

यह वास्तव में एक भयानक हैक है। सॉकेट को खोलने के लिए बेहतर है और इसका उपयोग करते रहें। – Imagist

+0

यदि आप प्रोटोकॉल को इसका समर्थन करने के लिए डिज़ाइन किया गया है, तो आप केवल इसका उपयोग कर सकते हैं, और सभी कनेक्शन एक ही स्थान पर हैं। बेशक यह बेहतर है कि आप इसे कर सकते हैं, लेकिन ओपी ने कहा कि सर्वर को जवाब देने से पहले कनेक्शन बंद होने की आवश्यकता है। – mark4o

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

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