बंद बनाम बंद सॉकेट?


214

सी में, मैं समझ गया कि यदि हम एक सॉकेट बंद करते हैं, तो इसका मतलब है कि सॉकेट नष्ट हो जाएगा और बाद में फिर से उपयोग किया जा सकता है।

शटडाउन के बारे में कैसे? विवरण में कहा गया है कि यह उस सॉकेट के डुप्लेक्स कनेक्शन का आधा हिस्सा बंद कर देता है। लेकिन क्या वह सॉकेट closeसिस्टम कॉल की तरह नष्ट हो जाएगा ?


इसे बाद में पुन: उपयोग नहीं किया जा सकता है। यह बंद है। ख़त्म होना। किया हुआ।
लोर्न

जवाबों:


191

यह बीजे के नेटवर्किंग गाइड में समझाया गया है। shutdownएक या दोनों दिशाओं में संचार को अवरुद्ध करने का एक लचीला तरीका है। जब दूसरा पैरामीटर होता है SHUT_RDWR, तो यह भेजने और प्राप्त करने (जैसे close) दोनों को अवरुद्ध करेगा । हालांकि, closeवास्तव में एक सॉकेट को नष्ट करने का तरीका है।

इसके साथ shutdown, आप अभी भी लंबित डेटा प्राप्त कर पाएंगे जो पहले से ही भेजा गया है (इस पर ध्यान देने के लिए जॉय एडम्स का धन्यवाद)।


23
ध्यान रखें, भले ही आप एक TCP सॉकेट बंद करें (), वैसे भी यह तुरंत पुन: उपयोग करने योग्य नहीं होगा, क्योंकि यह TIME_WAIT स्थिति में होगा, जबकि OS सुनिश्चित करता है कि कोई उत्कृष्ट पैकेट नहीं है जो नई जानकारी के रूप में भ्रमित हो सकता है यदि आप तुरंत कुछ और के लिए उस सॉकेट का पुन: उपयोग करने के लिए थे।
एल्सप्लिन

91
सॉकेट पर बंद और बंद होने के बीच बड़ा अंतर व्यवहार है जब सॉकेट को अन्य प्रक्रियाओं द्वारा साझा किया जाता है। एक शटडाउन () बंद होने के दौरान सॉकेट की सभी प्रतियों को प्रभावित करता है (एक प्रक्रिया में केवल फाइल डिस्क्रिप्टर को प्रभावित करता है।
ज़ैन लिंक्स

5
एक कारण हो सकता है कि आप shutdownदोनों दिशाओं का उपयोग करना चाहें, लेकिन ऐसा नहीं closeहै कि आपने उपयोग किए गए FILEसॉकेट का संदर्भ बनाया है fdopen। यदि आप closeसॉकेट, एक नई खोली गई फ़ाइल को एक ही fd सौंपा जा सकता है, और बाद में उपयोग FILEगलत जगह को पढ़ / लिख देगा जो बहुत बुरा हो सकता है। अगर आप बसshutdown , बाद में FILEवसीयत का उपयोग केवल त्रुटियों को दे देंगे जब तक fcloseकि बुलाया नहीं जाता है।
आर .. गिटहब स्टॉप हेल्पिंग ICE

25
TIME_WAIT के बारे में टिप्पणी गलत है। यह बंदरगाहों पर लागू होता है, न कि सॉकेट के लिए। आप सॉकेट्स का पुन: उपयोग नहीं कर सकते।
लोर्ने का मार्किस

48
-1। यह पोस्ट और लिंक दोनों एक महत्वपूर्ण वैचारिक कारण का उपयोग करना चाहते हैं shutdown: ईओएफ को सहकर्मी को संकेत देने के लिए और अभी भी लंबित डेटा प्राप्त करने में सक्षम हो।
जॉय एडम्स

144

मौजूदा जवाबों में से कोई भी लोगों को यह नहीं बताता कि कैसे shutdownऔरclose टीसीपी प्रोटोकॉल स्तर पर काम करता है, इसलिए इसे जोड़ने के लायक है।

एक मानक टीसीपी कनेक्शन 4-वे फाइनल करके समाप्त हो जाता है:

  1. एक बार एक प्रतिभागी के पास भेजने के लिए अधिक डेटा नहीं होता है, यह दूसरे को एक फिन पैकेट भेजता है
  2. दूसरी पार्टी फिन के लिए एक एसीके लौटाती है।
  3. जब दूसरी पार्टी ने भी डेटा ट्रांसफर खत्म कर दिया, तो यह एक और फिन पैकेट भेजती है
  4. प्रारंभिक प्रतिभागी एक ACK देता है और अंतरण को अंतिम रूप देता है।

हालाँकि, टीसीपी कनेक्शन को बंद करने का एक और "उभरता हुआ" तरीका है:

  1. एक प्रतिभागी एक RST पैकेट भेजता है और कनेक्शन को छोड़ देता है
  2. दूसरा पक्ष एक RST प्राप्त करता है और फिर कनेक्शन को छोड़ देता है

डिफ़ॉल्ट सॉकेट विकल्पों के साथ विंडसरक के साथ मेरे परीक्षण में, shutdownदूसरे छोर पर एक फिन पैकेट भेजता है , लेकिन यह सब होता है। जब तक दूसरी पार्टी आपको फिन पैकेट नहीं भेजती तब तक आप डेटा प्राप्त करने में सक्षम हैं। एक बार यह हो गया, आपकाReceive 0 आकार का परिणाम मिलेगा। इसलिए यदि आप "भेजने" को बंद करने वाले पहले व्यक्ति हैं, तो डेटा प्राप्त करने के बाद आपको सॉकेट बंद कर देना चाहिए।

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

नियमों के बारे में मेरी राय होगी:

  1. जब संभव हो shutdownपहले विचार करेंclose
  2. यदि आपने शटडाउन करने का निर्णय लेने से पहले (0 आकार का डेटा प्राप्त) समाप्त कर दिया है, तो अंतिम भेजने (यदि कोई हो) के बाद कनेक्शन बंद कर दें।
  3. यदि आप कनेक्शन को सामान्य रूप से बंद करना चाहते हैं, तो कनेक्शन को बंद करें (SHUT_WR के साथ, और यदि आप इस बिंदु के बाद डेटा प्राप्त करने के बारे में परवाह नहीं करते हैं, तो SHUT_RD के साथ भी), और तब तक प्रतीक्षा करें जब तक आप 0 आकार का डेटा प्राप्त न कर लें, और फिर बंद करें। सॉकेट।
  4. किसी भी स्थिति में, यदि कोई अन्य त्रुटि हुई (उदाहरण के लिए समय समाप्त), बस सॉकेट बंद करें।

SHUT_RD और SHUT_WR के लिए आदर्श कार्यान्वयन

निम्नलिखित का परीक्षण नहीं किया गया है, अपने जोखिम पर विश्वास करें। हालांकि, मेरा मानना ​​है कि यह चीजों को करने का एक उचित और व्यावहारिक तरीका है।

यदि टीसीपी स्टैक केवल SHUT_RD के साथ शटडाउन प्राप्त करता है, तो यह इस कनेक्शन को चिन्हित करेगा क्योंकि कोई अधिक डेटा अपेक्षित नहीं है। कोई भी लंबित और बाद में readअनुरोध (जो भी धागा हो, वे) फिर शून्य आकार के परिणाम के साथ वापस आ जाएंगे। हालाँकि, कनेक्शन अभी भी सक्रिय और प्रयोग करने योग्य है - आप अभी भी OOB डेटा प्राप्त कर सकते हैं, उदाहरण के लिए। इसके अलावा, ओएस इस कनेक्शन के लिए प्राप्त किसी भी डेटा को छोड़ देगा। लेकिन यह सब है, दूसरी तरफ कोई पैकेज नहीं भेजा जाएगा।

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


2
"यदि आप कॉल को बंद करते हैं, जबकि कनेक्शन अभी भी जीवित है" तना हुआ है, और यह एक RST भेजने का कारण नहीं बनता है। (१) आवश्यक नहीं है। (4) में, टाइमआउट आवश्यक रूप से कनेक्शन के लिए घातक नहीं है और अपरिवर्तनीय नहीं दर्शाती है कि आप इसे बंद कर सकते हैं।
लोर्ने का मार्कीस

4
@ ईजेपी नहीं, यह तांत्रिक नहीं है। आप shutdown()कनेक्शन कर सकते हैं और फिर यह जीवित नहीं है। आपके पास अभी भी फ़ाइल डिस्क्रिप्टर है। आप अभी भी recv()प्राप्त बफर से कर सकते हैं । और आपको अभी भी close()फ़ाइल डिस्क्रिप्टर को निपटाने के लिए कॉल करना होगा।
पावेल Paमेरदा

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

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

1
@EJP क्या आपके पास कोई वास्तविक तर्क है? वरना मुझे कोई दिलचस्पी नहीं है।
पावेल Paइमरदा

35

इसके साथ कुछ सीमाएँ हैं जिन्हें close()यदि कोई उपयोग करता है तो इससे बचा जा सकता है shutdown()

close()एक टीसीपी कनेक्शन पर दोनों दिशाओं को समाप्त करेगा। कभी-कभी आप दूसरे समापन बिंदु को बताना चाहते हैं कि आप डेटा भेजने के साथ समाप्त हो गए हैं, लेकिन फिर भी डेटा प्राप्त करना चाहते हैं।

close()डिस्क्रिप्टर रेफरेंस काउंट को घटाता है (फाइल टेबल एंट्री में बना रहता है और वर्तमान में खुलने वाले डिस्क्रिप्टर की संख्या गिना जाता है जो किसी फाइल / सॉकेट की ओर इशारा करते हैं) और सॉकेट / फाइल को बंद नहीं करता है यदि डिस्क्रिप्टर 0. नहीं है। इसका मतलब है कि आप फोर्किंग कर रहे हैं, क्लीनअप केवल रेफरेंस काउंट ड्रॉप्स के 0. के बाद होता है shutdown()। रेफरेंस काउंट को नजरअंदाज करते हुए सामान्य टीसीपी क्लोज सीक्वेंस शुरू कर सकता है।

पैरामीटर निम्नानुसार हैं:

int shutdown(int s, int how); // s is socket descriptor

int how हो सकता है:

SHUT_RDया 0 इसके अलावा प्राप्तियां अस्वीकृत हैं

SHUT_WRया 1 आगे भेजे गए अस्वीकृत हैं

SHUT_RDWRया 2 आगे भेजता है और प्राप्त होता है


8
दो कार्य पूरी तरह से अलग उद्देश्यों के लिए हैं। तथ्य यह है कि एक सॉकेट पर अंतिम करीबी एक शटडाउन अनुक्रम शुरू करता है अगर कोई पहले से ही शुरू नहीं किया गया है तो इस तथ्य को नहीं बदलता है कि सॉकेट डेटा संरचनाओं की सफाई के लिए करीब है और शटडाउन एक tcp स्तर शटडाउन अनुक्रम शुरू करने के लिए है।
लेन होल्गेट

25
आप इसके बजाय 'शटडाउन का उपयोग नहीं कर सकते'। आप इसका भी उपयोग कर सकते हैं लेकिन आपको कुछ समय सॉकेट बंद करना होगा।
लोर्ने

15

यह प्लेटफ़ॉर्म विशिष्ट हो सकता है, मुझे किसी तरह इस पर संदेह है, लेकिन फिर भी, मैंने जो सबसे अच्छा विवरण देखा है वह इस एमएसडीएन पृष्ठ पर है जहां वे शटडाउन, लिंगर विकल्प, सॉकेट बंद करने और सामान्य कनेक्शन समाप्ति अनुक्रम के बारे में बताते हैं।

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


9

मैं भी shutdown()एक pthread का उपयोग कर linux के तहत सफलता मिली है एक और pthread मजबूर करने के लिए वर्तमान में अवरुद्ध हैconnect() करने के लिए जल्दी से ।

अन्य OSes (OSX कम से कम) के तहत, मैंने पाया close()कि connect()असफल होने के लिए कॉलिंग पर्याप्त थी ।


7

"शटडाउन () वास्तव में फ़ाइल डिस्क्रिप्टर को बंद नहीं करता है - यह सिर्फ इसकी प्रयोज्यता को बदलता है। सॉकेट डिस्क्रिप्टर को मुक्त करने के लिए, आपको बंद () का उपयोग करने की आवश्यकता है।" 1


3

बंद करे

जब आपने सॉकेट का उपयोग करना समाप्त कर लिया है, तो आप बस इसके फ़ाइल डिस्क्रिप्टर को बंद कर सकते हैं; यदि कनेक्शन पर प्रेषित होने के लिए अभी भी डेटा है, तो सामान्य रूप से करीब इस ट्रांसमिशन को पूरा करने की कोशिश करता है। टाइमआउट अवधि निर्दिष्ट करने के लिए SO_LINGER सॉकेट विकल्प का उपयोग करके आप इस व्यवहार को नियंत्रित कर सकते हैं; सॉकेट विकल्प देखें।

बंद करना

आप शटडाउन कॉल करके कनेक्शन पर केवल रिसेप्शन या ट्रांसमिशन को भी बंद कर सकते हैं।

शटडाउन फ़ंक्शन सॉकेट के कनेक्शन को बंद कर देता है। इसका तर्क यह बताता है कि प्रदर्शन करने की क्रिया क्या है: 0 इस सॉकेट के लिए डेटा प्राप्त करना बंद करें। यदि आगे डेटा आता है, तो इसे अस्वीकार करें। 1 इस सॉकेट से डेटा प्रसारित करने की कोशिश करना बंद करें। भेजे जाने वाले किसी भी डेटा को छोड़ दें। पहले से भेजे गए डेटा की पावती की तलाश करना बंद करें; अगर यह खो गया है तो इसे दोबारा न लें। 2 स्वागत और प्रसारण दोनों बंद करो।

वापसी का मूल्य सफलता पर 0 और असफलता पर -1 है।


2

मेरे परीक्षण में

close जब सॉकेट अन्य प्रक्रियाओं के साथ साझा नहीं किया जाता है, तो फ़ाइ पैकेट भेज देगा और fd को नष्ट कर देगा

shutdown SHUT_RD , प्रोसेस अभी भी सॉकेट से डेटा रिकवर कर सकता है, लेकिन recvTCP बफर खाली होने पर 0 वापस आएगा। सहकर्मी अधिक डेटा भेजने के बाद, recvडेटा फिर से लौटाएगा।

shutdown SHUT_WR आगे के पैकेट बंद होने का संकेत देने के लिए फिन पैकेट भेजेगा। सहकर्मी डेटा रिकवर कर सकता है लेकिन यदि उसका TCP बफर खाली है तो वह 0 recv करेगा

shutdown SHUT_RDWR (दोनों SHUT_RD और SHUT_WR का उपयोग करने के लिए बराबर ) rst पैकेट भेजेगा यदि सहकर्मी अधिक डेटा भेजता है।


मैंने बस कोशिश की और close()फिन के बजाय लिनक्स पर आरएसटी भेजा।
पावेल Paमरदा

क्या आप वास्तव में यह बताना चाहते हैं कि रीडिंग साइड को बंद करने के बाद, प्रोग्राम को अधिक डेटा प्राप्त होगा?
पावेल Paमेरदा

@ Pavel onimerda मुझे लगता है कि यह आरएसटी या फिन भेजने के लिए टीसीपी राज्य पर निर्भर हो सकता है? मुझे यकीन नहीं है।
सिमबॉक्स

1. 'सहकर्मी अधिक डेटा भेजने के बाद, recv()डेटा फिर से लौटाएगा' सही नहीं है। 2. SHUT_RDमंच-निर्भर होने के बाद सहकर्मी अधिक डेटा भेजता है तो व्यवहार ।
लोर्ने

@ ईजेपी मैंने खुद की कोशिश की, माफ करना मैं भूल जाता हूं कि यह परीक्षण मैं किस प्लेटफॉर्म, सेंटो या मैक पर करता हूं। और यह वही है जो मुझे मिला
simpx
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.