2010-04-11 6 views
19

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

उदाहरण के लिए यह एक आम योजना का एक सरल उदाहरण है:

 
int send_all(int sock, unsigned char *buffer, int len) { 
    int nsent; 

    while(len > 0) { 
    nsent = send(sock, buffer, len, 0); 
    if(nsent == -1) // error 
     return -1; 

    buffer += nsent; 
    len -= nsent; 
    } 
    return 0; // ok, all data sent 
} 

भी बीएसडी मैनपेज कहा गया है कि

... अगर कोई संदेश अंतरिक्ष सॉकेट पर उपलब्ध है संदेश धारण करने के लिए प्रेषित किया है, तो भेज() सामान्य रूप से ब्लॉक ...

कौन सा मतलब है कि हम यह मान लेना चाहिए कि भेजने सभी डेटा भेजे बिना वापस आ सकते हैं । अब मुझे यह टूटा हुआ है लेकिन यहां तक ​​कि डब्ल्यू। रिचर्ड स्टीवंस इसे अपने मानक संदर्भ पुस्तक में network programming में मानते हैं, शुरुआत अध्यायों में नहीं, लेकिन अधिक उन्नत उदाहरण लिखने के बजाए अपने स्वयं के लेख (सभी डेटा लिखें) फ़ंक्शन का उपयोग करते हैं।

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

मेरा मतलब है, ऊपर दिए गए कोड उदाहरण में, यदि डेटा कम डेटा के साथ रिटर्न भेजता है तो यह होगा कि इसे फिर से एक नए अनुरोध के साथ बुलाया जाएगा। आखिरी कॉल के बाद क्या बदल गया है? अधिकतम कुछ सौ CPU चक्र पारित हो गए हैं इसलिए बफर अभी भी भरा हुआ है। अगर अब डेटा स्वीकार करता है तो इसे पहले क्यों स्वीकार नहीं किया जा सकता था?

अन्यथा हम एक अक्षम लूप के साथ समाप्त हो जाएंगे जहां हम एक सॉकेट पर डेटा भेजने की कोशिश कर रहे हैं जो डेटा स्वीकार नहीं कर सकता है और कोशिश कर रहा है, या नहीं?

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

उत्तर

17

उपरोक्त विवरण में अनुपलब्ध चीज यूनिक्स में है, सिस्टम कॉल सिग्नल के साथ बाधित हो सकती है। send(2) को अवरुद्ध करने का यही कारण है कि एक छोटी सी गिनती हो सकती है।

+1

क्या इसका परिणाम ईआईएनटीआर में नहीं होगा? या ईआईएनटीआर केवल तब होगा जब किसी भी डेटा को http://www.manpagez.com/man/2/send/ में वर्णित अनुसार संसाधित किया जाता है और यदि डेटा भेजा गया है, तो ईआईएनटीआर जारी नहीं किया गया है, और इसके बजाय राशि भेजा गया डेटा वापस कर दिया गया है? – Ernelli

+2

ईआईएनटीआर केवल तभी लौटाया जाता है जब कोई डेटा अभी तक स्थानांतरित नहीं किया गया हो (और सिग्नल हैंडलर SA_RESTART ध्वज के साथ स्थापित नहीं किया गया था)। – mark4o

+2

क्या वास्तव में यही कारण है? क्या इसका मतलब यह होगा कि, अगर मैं कोई सिग्नल हैंडलर इंस्टॉल नहीं करता हूं, तो भेजने के चारों ओर लूप अनावश्यक होगा? इससे मेरे लिए चीजों को थोड़ा सा सरल बना दिया जाएगा। दुर्भाग्यवश, इस मामले पर दस्तावेज बहुत दुर्लभ प्रतीत होता है ... – lxgr

0

यह एक कुशल परिवहन तंत्र के लिए एक बहुत ही आवश्यक आवश्यकता है जिसमें डिवाइस ड्राइवर शामिल हैं। ढेर का राजा टीसीपी है, इससे कोई फर्क नहीं पड़ता कि आप इसमें क्या फेंकते हैं, यह तार के डेटा को प्राप्त करने के लिए अपना स्तर सबसे अच्छा करेगा। यह काफी अच्छा है, इसमें 9 नाइन डिलीवरी गारंटी है। इसे आम तौर पर पृथ्वी के भूकंप की आवश्यकता होती है या कोई व्यक्ति उस वादे को पूरा न करने के लिए एक पावर कॉर्ड पर जा रहा है।

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

अच्छी बात। अगर किसी कारण से आपकी डिलीवरी गारंटी उस से मजबूत होनी चाहिए, शायद 12 नाइन, तो आपको टीसीपी का उपयोग नहीं करना चाहिए। यह किया गया है, "विश्वसनीय यूडीपी" अच्छी तरह से googles। हालांकि यह बार-बार फिर से आविष्कार किया जाता है। सौभाग्य!

+2

मैंने सवाल पूछने का कारण यह था कि चूंकि ब्लॉकिंग या गैर अवरोधन मोड दोनों में सॉकेट बनाया जा सकता है। अवरुद्ध मोड को लगातार तरीके से व्यवहार करना चाहिए उदा। अपने अनुबंध को पूरा करें कि, उदाहरण के लिए हमेशा भेजे गए पूरे संदेश को स्वीकार करते हैं, अन्यथा यह अवरुद्ध होगा। यदि सॉकेट दोनों अवरुद्ध और गैर अवरोधन मोड में समान व्यवहार करता है, तो कभी भी ब्लॉकिंग/गैर अवरोधक सॉकेट में कोई बिंदु नहीं है। निकोलाई का जवाब बताता है कि ऐसा क्यों हो सकता है, लेकिन मुझे अभी भी विश्वास नहीं है क्योंकि उस स्थिति को एक ईआईएनटीआर ट्रिगर करना चाहिए और एक छोटा सा लेखन नहीं होना चाहिए। – Ernelli

+1

इसमें '9 नाइन डिलीवरी गारंटी' जैसी कोई चीज़ नहीं है। इसमें 'सर्वश्रेष्ठ प्रयास' वितरण गारंटी है, और व्यवहार में यह बहुत अच्छा है, लेकिन कहीं भी '9 नाइन' के पास नहीं है। – EJP

+0

@ एर्नेली: गैर-अवरुद्ध सॉकेट का बिंदु _never_ ब्लॉक है। जब तक वे अपना काम नहीं करते हैं, तब तक सॉकेट ओटीओएच ब्लॉक को अवरुद्ध करते हैं, या कुछ _exceptional_ स्थिति उत्पन्न होती है। – ninjalj

0

अनिवार्य रूप से, व्यवहार केवल लचीलापन जोड़ता है।

विचार करें कि क्या होता है यदि आंतरिक प्रेषक बफर के पास 300 बाइट्स के लिए कमरा होता है, और आप 800 बाइट भेजने के लिए send() से पूछते हैं।

क्या होता है यह है कि यह पहले 300 बाइट स्वीकार करता है और उन्हें सॉकेट बफर में रखता है, फिर रिटर्न देता है। यदि आप वास्तव में सभी 800 बाइट्स तक चले जाने तक ब्लॉक करना चाहते हैं, तो आप पिछले 500 बाइट्स के लिए send() को फिर से कॉल करें, और यह ब्लॉक करेगा (क्योंकि प्रेषण बफर अब पूर्ण हो गया है)। दूसरी तरफ, यदि आप अब कुछ और करना चाहते हैं, और बाद में शेष 500 बाइट्स भेजने का प्रयास करें, तो आप भी ऐसा कर सकते हैं।

+5

यदि वह लचीलापन किसी भी उपयोग का है, तो एक गैर अवरोधक सॉकेट का उपयोग किया जाना चाहिए। – Ernelli

+1

@caf: उस मामले में, 'भेजें() 'को पॉज़िक्स के अनुसार पर्याप्त बफर स्पेस (या सिग्नल द्वारा बाधित होने जैसी असाधारण स्थिति) तक अवरुद्ध करना चाहिए। बेशक, न्यूनतम नेटवर्क स्टैक कार्यान्वयन के व्यवहार (यूआईपी, एलडब्ल्यूआईपी, ...) भिन्न हो सकते हैं। – ninjalj

+1

-1: एक बहुत छोटा आंतरिक बफर मामला नहीं हो सकता है, क्योंकि 'प्रेषण'/'लिखना 'अवरुद्ध हो रहा है। – Flow

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