I / O का प्रयास किए बिना यह असंभव क्यों है, यह पता लगाने के लिए कि TCP सॉकेट को सहकर्मी द्वारा बंद कर दिया गया था?


92

हाल ही में एक प्रश्न के अनुवर्ती के रूप में , मुझे आश्चर्य है कि टीसीपी सॉकेट पर पढ़ने / लिखने का प्रयास किए बिना जावा में यह असंभव क्यों है, यह पता लगाने के लिए कि सॉकेट को सहकर्मी द्वारा बंद कर दिया गया है? यह इस बात की परवाह किए बिना होता है कि कोई पूर्व-NIO Socketया NIO का उपयोग करता है या नहीं SocketChannel

जब कोई सहकर्मी किसी टीसीपी कनेक्शन को बंद करता है, तो कनेक्शन के दोनों तरफ स्थित टीसीपी स्टैक तथ्य के बारे में जानता है। सर्वर-साइड (शटडाउन शुरू करने वाला) राज्य में समाप्त होता है FIN_WAIT2, जबकि क्लाइंट-साइड (वह जो शटडाउन का स्पष्ट रूप से जवाब नहीं देता है) राज्य में समाप्त होता है CLOSE_WAIT। इसमें कोई विधि क्यों नहीं है Socketया SocketChannelयह देखने के लिए TCP स्टैक को क्वेरी कर सकता है कि क्या अंतर्निहित TCP कनेक्शन समाप्त कर दिया गया है? क्या यह है कि टीसीपी स्टैक ऐसी स्थिति जानकारी प्रदान नहीं करता है? या यह कर्नेल में एक महंगी कॉल से बचने के लिए एक डिजाइन निर्णय है?

उन उपयोगकर्ताओं की मदद से जिन्होंने पहले से ही इस प्रश्न के कुछ उत्तर पोस्ट किए हैं, मुझे लगता है कि मैं देख रहा हूं कि समस्या कहां से आ रही है। जो पक्ष कनेक्शन को स्पष्ट रूप से बंद नहीं करता है वह टीसीपी राज्य में समाप्त होता है CLOSE_WAITजिसका अर्थ है कि कनेक्शन बंद करने की प्रक्रिया में है और पक्ष द्वारा स्वयं के CLOSEसंचालन को जारी करने की प्रतीक्षा करता है । मुझे लगता है कि यह काफी उचित है कि isConnectedरिटर्न trueऔर isClosedरिटर्न false, लेकिन ऐसा कुछ क्यों नहीं है isClosing?

नीचे परीक्षण कक्षाएं हैं जो पूर्व-एनआईओ सॉकेट का उपयोग करती हैं। लेकिन NIO का उपयोग करके समान परिणाम प्राप्त किए जाते हैं।

import java.net.ServerSocket;
import java.net.Socket;

public class MyServer {
  public static void main(String[] args) throws Exception {
    final ServerSocket ss = new ServerSocket(12345);
    final Socket cs = ss.accept();
    System.out.println("Accepted connection");
    Thread.sleep(5000);
    cs.close();
    System.out.println("Closed connection");
    ss.close();
    Thread.sleep(100000);
  }
}


import java.net.Socket;

public class MyClient {
  public static void main(String[] args) throws Exception {
    final Socket s = new Socket("localhost", 12345);
    for (int i = 0; i < 10; i++) {
      System.out.println("connected: " + s.isConnected() + 
        ", closed: " + s.isClosed());
      Thread.sleep(1000);
    }
    Thread.sleep(100000);
  }
}

जब परीक्षण क्लाइंट परीक्षण सर्वर से जुड़ता है तो सर्वर कनेक्शन के बंद होने के बाद भी आउटपुट अपरिवर्तित रहता है:

connected: true, closed: false
connected: true, closed: false
...

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

2
हमारे पास दो मेलबॉक्स (सॉकेट) हैं ..........................................। ...... रॉयलबॉक्स (IP) का उपयोग करते हुए मेलबॉक्स प्रत्येक मेल को मेल भेजते हैं, टीसीपी के बारे में भूल जाते हैं ............................। .................... सभी ठीक है और बांका है, मेलबॉक्स कोई समस्या नहीं होने पर प्रत्येक को मेल भेज सकता है (हाल ही में लोड के अंतराल) भेज सकता है। ............. अगर एक मेलबॉक्स ट्रक की चपेट में आ गया और असफल हो गया .... तो दूसरे मेलबॉक्स को कैसे पता चलेगा? यह रॉयल मेल द्वारा सूचित किया जाना चाहिए, जो बदले में इसे अगले असफल मेलबॉक्स से भेजने / प्राप्त करने की कोशिश नहीं कर पता होगा। ......
erm

यदि आप सॉकेट से पढ़ने या सॉकेट पर लिखने नहीं जा रहे हैं, तो आप क्यों परवाह करते हैं? और अगर आप सॉकेट से पढ़ने जा रहे हैं या सॉकेट पर लिख रहे हैं, तो अतिरिक्त जांच क्यों करें? उपयोग मामला क्या है?
डेविड श्वार्ट्ज

2
Socket.closeएक सुंदर करीबी नहीं है।
user253751

@ मिनीबिस यह सबसे निश्चित रूप से एक ग्रेसफुल क्लोज है, जब तक सॉकेट में अनरीड डेटा बफर नहीं मिलता है या आपने SO_LINGER के साथ गड़बड़ कर दी है।
लोरने का मार्किस

जवाबों:


29

मैं अक्सर सॉकेट्स का उपयोग करता रहा हूं, ज्यादातर चयनकर्ताओं के साथ, और हालांकि मेरी समझ से एक नेटवर्क ओएसआई विशेषज्ञ नहीं है, shutdownOutput()सॉकेट पर कॉल करना वास्तव में नेटवर्क (फिन) पर कुछ भेजता है जो मेरे चयनकर्ता को दूसरी तरफ जगाता है (सी में समान व्यवहार) भाषा: हिन्दी)। यहां आपके पास डिटेक्शन है : वास्तव में रीड ऑपरेशन का पता लगाना जो आपके द्वारा प्रयास करने पर विफल हो जाएगा।

आपके द्वारा दिए गए कोड में, सॉकेट को बंद करना इनपुट और आउटपुट स्ट्रीम दोनों को बंद कर देगा, बिना उपलब्ध डेटा को पढ़ने की संभावनाओं के बिना, इसलिए उन्हें खो देना। जावा Socket.close()विधि एक "ग्रेसफुल" वियोग (जैसा कि मैंने शुरू में सोचा था) के विपरीत करता है, जिसमें आउटपुट स्ट्रीम में छोड़े गए डेटा को इसके करीब पहुंचने के लिए एक फिन द्वारा भेजा जाएगा । फिन दूसरी तरफ से ACK'd होगा, क्योंकि कोई भी नियमित पैकेट 1 होगा ।

यदि आपको इसके सॉकेट को बंद करने के लिए दूसरे पक्ष की प्रतीक्षा करने की आवश्यकता है, तो आपको इसके फिन की प्रतीक्षा करने की आवश्यकता है। और वह प्राप्त करने के लिए, आप के लिए है का पता लगाने के Socket.getInputStream().read() < 0जो मतलब है कि आप करना चाहिए, नहीं पास अपने सॉकेट, के रूप में यह होता है इसके बंदInputStream

सी में मैंने क्या किया, और अब जावा में, इस तरह के एक समकालिक को प्राप्त करना इस तरह से किया जाना चाहिए:

  1. शटडाउन सॉकेट आउटपुट (दूसरे छोर पर फिन भेजता है, यह आखिरी चीज है जिसे कभी भी इस सॉकेट द्वारा भेजा जाएगा)। इनपुट अभी भी खुला है ताकि आप read()रिमोट का पता लगा सकेंclose()
  2. सॉकेट पढ़ें InputStreamजब तक कि हम दूसरे छोर से उत्तर-फिन प्राप्त नहीं करते (जैसा कि यह एफआई का पता लगाएगा, यह एक ही सुंदर डायनिकनेशन प्रक्रिया से गुजरेगा)। कुछ OS पर यह महत्वपूर्ण है क्योंकि वे वास्तव में सॉकेट को बंद नहीं करते हैं जब तक कि उसके एक बफर में अभी भी डेटा शामिल नहीं है। उन्हें "घोस्ट" सॉकेट कहा जाता है और ओएस में डिस्क्रिप्टर नंबर का उपयोग करते हैं (जो कि आधुनिक ओएस के साथ अब कोई मुद्दा नहीं हो सकता है)
  3. सॉकेट बंद करें (या तो कॉल करके या Socket.close()उसके InputStreamया बंद करके OutputStream)

जैसा कि निम्नलिखित जावा स्निपेट में दिखाया गया है:

public void synchronizedClose(Socket sok) {
    InputStream is = sok.getInputStream();
    sok.shutdownOutput(); // Sends the 'FIN' on the network
    while (is.read() > 0) ; // "read()" returns '-1' when the 'FIN' is reached
    sok.close(); // or is.close(); Now we can close the Socket
}

बेशक दोनों पक्षों को बंद करने के समान तरीके का उपयोग करना है, या whileलूप को व्यस्त रखने के लिए भेजने वाला हिस्सा हमेशा पर्याप्त डेटा भेज सकता है (उदाहरण के लिए यदि भेजने वाला हिस्सा केवल डेटा भेज रहा है और कनेक्शन समाप्ति का पता लगाने के लिए पढ़ना कभी नहीं है। जो कि अनाड़ी है, लेकिन आपका उस पर नियंत्रण नहीं हो सकता है)।

जैसा कि @WarrenDew ने अपनी टिप्पणी में बताया, प्रोग्राम (एप्लिकेशन लेयर) में डेटा को छोड़ना, एप्लिकेशन लेयर में एक गैर-अनुग्रहपूर्ण वियोग को प्रेरित करता है: हालांकि सभी डेटा TCP लेयर ( whileलूप) पर प्राप्त किए गए थे , उन्हें छोड़ दिया गया है।

1 : " फंडामेंटल नेटवर्किंग इन जावा " से: अंजीर देखें। 3.3 p.45, और संपूर्ण whole3.7, पीपी 43-48


जावा एक सुंदर करीबी प्रदर्शन करता है। यह 'क्रूर' नहीं है।
लोर्ने

2
@EJP, "ग्रेसफुल डिसकनेक्शन" टीसीपी स्तर पर होने वाला एक विशिष्ट एक्सचेंज है, जहां क्लाइंट को सर्वर को डिस्कनेक्ट करने के लिए अपनी इच्छा को संकेत देना चाहिए, जो बदले में, अपना पक्ष बंद करने से पहले शेष डेटा भेजता है। "शेष डेटा भेजें" भाग को कार्यक्रम द्वारा नियंत्रित किया जाना है (हालांकि लोग ज्यादातर समय कुछ भी नहीं भेजेंगे)। कॉलिंग socket.close()"क्रूर" है जिस तरह से यह क्लाइंट / सर्वर सिग्नलिंग का सम्मान नहीं करता है। सर्वर को केवल तब ग्राहक के वियोग के बारे में सूचित किया जाएगा जब उसका स्वयं का सॉकेट आउटपुट बफर भरा हुआ हो (क्योंकि कोई भी डेटा दूसरी तरफ से बंद नहीं किया जा रहा है, जो बंद था)।
Matthieu

अधिक जानकारी के लिए MSDN देखें ।
Matthieu

जावा अनुप्रयोगों को पहले सॉकेट.क्लोज () के बजाय 'शेष [शेष] शेष डेटा' भेजने के लिए मजबूर नहीं करता है, और यह उन्हें पहले शटडाउन का उपयोग करने से नहीं रोकता है। सॉकेट.क्लोज () बस वही करता है जो (sd) करता है। बर्कले सॉकेट्स एपीआई से जावा इस संबंध में अलग नहीं है। वास्तव में, ज्यादातर मामलों में।
लोर्ने का मार्कीट

2
@LeonidUsov यह केवल गलत है। जावा read()स्ट्रीम के अंत में -1 लौटाता है, और ऐसा तब भी जारी रहता है, जब आप इसे कॉल करते हैं। स्ट्रीम के अंत में AC read()या recv()शून्य वापस आता है, और ऐसा तब भी जारी रहता है, जब आप इसे कॉल करते हैं।
लोर्ने

18

मुझे लगता है कि यह एक सॉकेट प्रोग्रामिंग प्रश्न है। जावा केवल सॉकेट प्रोग्रामिंग परंपरा का पालन कर रहा है।

से विकिपीडिया :

टीसीपी एक प्रोग्राम पर एक कंप्यूटर से दूसरे कंप्यूटर पर एक प्रोग्राम से बाइट्स की स्ट्रीम का विश्वसनीय, ऑर्डर की गई डिलीवरी प्रदान करता है।

एक बार हैंडशेक करने के बाद, टीसीपी दो अंतिम बिंदुओं (क्लाइंट और सर्वर) के बीच कोई अंतर नहीं करता है। "क्लाइंट" और "सर्वर" शब्द ज्यादातर सुविधा के लिए है। इसलिए, "सर्वर" डेटा भेज सकता है और "क्लाइंट" एक-दूसरे को कुछ डेटा एक साथ भेज सकता है।

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

इसके अलावा, आप एक कार्यक्रम के रूप में, बफर में क्या है यह जाँचने के लिए समय नहीं रख सकते। इसलिए, अपनी सुविधानुसार आप जाँच कर सकते हैं कि बफर में क्या है। सब सब में, वर्तमान सॉकेट कार्यान्वयन इतना बुरा नहीं है। अगर वास्तव में वहाँ थे PeperClosed (), कि अतिरिक्त कॉल करने के लिए आप हर बार जब आप पढ़ने के लिए कॉल करना चाहते हैं।


1
मुझे नहीं लगता, आप दोनों विंडो और लिनक्स पर सी कोड में राज्यों के लिए परीक्षण कर सकते हैं !!! जावा किसी कारण से कुछ सामान को उजागर नहीं कर सकता है, जैसे कि विंडोज़ और लाइनक्स पर मिलने वाले गेटस्कॉप कार्यों को उजागर करना अच्छा होगा। वास्तव में, नीचे दिए गए उत्तरों में लिनक्स पक्ष के लिए कुछ लिनक्स सी कोड हैं।
डीन हिलर

मुझे नहीं लगता है कि'PPerClosed () 'विधि होने से किसी भी तरह से आप इसे हर पढ़ने के प्रयास से पहले कॉल कर सकते हैं। आप इसे केवल तभी कॉल कर सकते हैं जब आपको स्पष्ट रूप से इसकी आवश्यकता हो। मैं मानता हूं कि वर्तमान सॉकेट कार्यान्वयन इतना बुरा नहीं है, भले ही इसके लिए आपको आउटपुट स्ट्रीम पर लिखना होगा, अगर आप यह जानना चाहते हैं कि सॉकेट का रिमोट हिस्सा बंद है या नहीं। क्योंकि यदि यह नहीं है, तो आपको अपना लिखित डेटा दूसरी तरफ भी संभालना होगा, और यह बस के रूप में खड़ी नेल पर बैठे हुए आनंद के रूप में बड़ी मात्रा में है;)
जन हर्बी

1
यह करता है मतलब 'वहाँ उड़ान में कोई और अधिक पैकेट है'। उड़ान में किसी भी डेटा के बाद फिन प्राप्त होता है । हालाँकि इसका मतलब यह नहीं है कि सहकर्मी ने इनपुट के लिए सॉकेट बंद कर दिया है आपको ** कुछ भेजना होगा * और पता लगाने के लिए एक 'कनेक्शन रीसेट' प्राप्त करना होगा। फिन का मतलब सिर्फ आउटपुट के लिए शटडाउन हो सकता है।
लोर्ने

11

अंतर्निहित सॉकेट API में ऐसी कोई सूचना नहीं है।

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


मेरे परीक्षण उदाहरण में (शायद मुझे यहां एक प्रदान करना चाहिए ...) उद्देश्य पर कनेक्शन पर कोई डेटा भेजा / प्राप्त नहीं किया गया है। इसलिए, मुझे पूरा यकीन है कि स्टैक फिन (सुशोभित) या आरएसटी (कुछ गैर-सुंदर परिदृश्यों में) प्राप्त करता है। यह भी netstat द्वारा पुष्टि की है।
अलेक्जेंडर

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

1
क्या होता है कि कनेक्शन के पक्ष <code> CLOSE_WAIT </ code> और <code> FIN_WAIT_2 </ code> में समाप्त हो जाते हैं और यह इस अवस्था में है <code> isConcected () </ code> और <code> isClosed () </ code> अभी भी यह नहीं देखता कि कनेक्शन समाप्त कर दिया गया है।
अलेक्जेंडर

आपके सुझाव के लिए धन्यवाद! मुझे लगता है कि मैं इस मुद्दे को अब बेहतर तरीके से समझता हूं। मैंने प्रश्न को और अधिक विशिष्ट बना दिया (तीसरा पैराग्राफ देखें): आधे-बंद कनेक्शन के लिए परीक्षण करने के लिए "सॉकेट.इस क्लोजिंग" क्यों नहीं है?
अलेक्जेंडर

8

चूंकि अब तक कोई भी उत्तर पूरी तरह से सवाल का जवाब नहीं दे रहा है, इसलिए मैं इस मुद्दे की अपनी वर्तमान समझ का सारांश प्रस्तुत कर रहा हूं।

जब एक टीसीपी कनेक्शन स्थापित होता है और एक पीयर कॉल close()या shutdownOutput()उसके सॉकेट पर, कनेक्शन ट्रांसक्शन के दूसरी तरफ सॉकेट CLOSE_WAITराज्य में होता है। सिद्धांत रूप में, टीसीपी स्टैक से यह पता लगाना संभव है कि क्या सॉकेट CLOSE_WAITबिना कॉल किए राज्य में है read/recv(उदाहरण के लिए, getsockopt()लिनक्स पर: http://www.developerweb.net/forum/showthread.php?t=4395 ), लेकिन यह नहीं है पोर्टेबल।

Socketलगता है कि जावा की कक्षा को बीएसडी टीसीपी सॉकेट के लिए एक अमूर्तता प्रदान करने के लिए डिज़ाइन किया गया है, शायद क्योंकि यह एब्सट्रैक्शन का स्तर है जिसके लिए लोग टीसीपी / आईपी अनुप्रयोगों को प्रोग्रामिंग करते समय उपयोग करते हैं। बीएसडी सॉकेट केवल INET (जैसे, टीसीपी) वाले लोगों के अलावा सॉकेट का समर्थन करने वाला एक सामान्यीकरण है, इसलिए वे सॉकेट की टीसीपी स्थिति का पता लगाने का एक पोर्टेबल तरीका प्रदान नहीं करते हैं।

ऐसा कोई तरीका नहीं है isCloseWait()क्योंकि BSD सॉकेट्स द्वारा की पेशकश की गई अमूर्तता के स्तर पर लोग टीसीपी अनुप्रयोगों को प्रोग्रामिंग करने के लिए उपयोग करते हैं, जावा को किसी भी अतिरिक्त तरीके प्रदान करने की उम्मीद नहीं है।


3
न ही जावा, कोई अतिरिक्त तरीके प्रदान कर सकता है । हो सकता है कि वे एक isCloseWait () विधि बना सकते हैं, जो यदि प्लेटफ़ॉर्म इसका समर्थन नहीं करता है, तो यह गलत होगा, लेकिन यदि उन्हें केवल समर्थित प्लेटफ़ॉर्म पर परीक्षण किया जाता है, तो कितने प्रोग्रामर को उस गेटा से काट लिया जाएगा?

1
ऐसा लगता है कि यह मेरे लिए पोर्टेबल हो सकता है ... विंडोज़ में यह msdn.microsoft.com/en-us/library/windows/desktop/… और linux this pubs.opengroup.org/onlinepubs/009695399/functions/…
डीन हिलर है

1
ऐसा नहीं है कि प्रोग्रामर इसका उपयोग करते हैं; यह है कि सॉकेट इंटरफ़ेस प्रोग्रामर के लिए उपयोगी है। ध्यान रखें कि सॉकेट अमूर्त का उपयोग टीसीपी प्रोटोकॉल से अधिक के लिए किया जाता है।
वारेन ड्यू

जावा में कोई विधि नहीं है isCloseWait()क्योंकि यह सभी प्लेटफार्मों पर समर्थित नहीं है।
लोर्ने

पहचान (RFC 1413) प्रोटोकॉल सर्वर को प्रतिक्रिया भेजने के बाद या तो कनेक्शन को खुला रखने की अनुमति देता है, या किसी और डेटा को भेजे बिना बंद कर देता है। एक जावा पहचान क्लाइंट अगले लुकअप पर 3-वे हैंडशेक से बचने के लिए कनेक्शन को खुला रखने का विकल्प चुन सकता है, लेकिन यह कैसे पता चलता है कि कनेक्शन अभी भी खुला है? क्या कनेक्शन को फिर से खोलकर किसी भी त्रुटि का जवाब देना चाहिए? या कि प्रोटोकॉल डिजाइन त्रुटि है?
डेविड

7

यह पता लगाना कि क्या (टीसीपी) सॉकेट कनेक्शन के रिमोट साइड को java.net.Socket.sendUrgentData (int) विधि से किया जा सकता है, और IOException को पकड़कर यह फेंकता है यदि रिमोट साइड नीचे है। यह जावा-जावा और जावा-सी के बीच परीक्षण किया गया है।

यह कुछ प्रकार के पिंगिंग तंत्र का उपयोग करने के लिए संचार प्रोटोकॉल को डिजाइन करने की समस्या से बचा जाता है। एक सॉकेट (सेटऑबइनलाइन (गलत) पर OOBInline को अक्षम करके, प्राप्त किसी भी OOB डेटा को चुपचाप छोड़ दिया जाता है, लेकिन OOB डेटा अभी भी भेजा जा सकता है। यदि दूरस्थ पक्ष बंद है, तो कनेक्शन रीसेट का प्रयास किया जाता है, विफल होता है और कुछ IOException को फेंकने का कारण बनता है। ।

यदि आप वास्तव में अपने प्रोटोकॉल में OOB डेटा का उपयोग करते हैं, तो आपका माइलेज अलग-अलग हो सकता है।


4

जावा आईओ स्टैक निश्चित रूप से फिन भेजता है जब यह एक अचानक फाड़ पर नष्ट हो जाता है। इसका कोई मतलब नहीं है कि आप इसका पता नहीं लगा सकते, b / c अधिकांश क्लाइंट केवल फिन को भेजते हैं यदि वे कनेक्शन बंद कर रहे हैं।

... एक और कारण मैं वास्तव में एनआईओ जावा कक्षाओं से नफरत करने लगा हूं। ऐसा लगता है जैसे सब कुछ थोड़ा आधा गधा है।


1
यह भी प्रतीत होता है कि मैं केवल पढ़ता हूं और अंत में धारा (1 रिटर्न) पढ़ता हूं जब एक एफआई मौजूद होता है। तो यह एकमात्र तरीका है जिसे मैं पढ़ने के पक्ष में एक शटडाउन का पता लगाने के लिए देख सकता हूं।

3
आप इसका पता लगा सकते हैं। पढ़ते समय आपको ई.ओ.एस. और Java फ़ाइनल नहीं भेजता है। टीसीपी वह करता है। जावा टीसीपी / आईपी को लागू नहीं करता है, यह सिर्फ प्लेटफॉर्म कार्यान्वयन का उपयोग करता है।
लोरेन

4

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

(अंतिम बिंदु पर दोनों की नज़दीकी स्थिति को पढ़ने के लिए दो तरीके हैं।)

दूसरी समस्या यह है कि कार्यान्वयन का कहना है कि यह व्यवहार वैकल्पिक है। जैसा कि जावा पोर्टेबल होने का प्रयास करता है, उन्होंने सबसे अच्छी सामान्य सुविधा को लागू किया। मुझे लगता है कि (ओएस, आधा डुप्लेक्स का कार्यान्वयन) का एक नक्शा बनाए रखना एक समस्या होगी।


1
मुझे लगता है कि आप RFC 793 के बारे में बात कर रहे हैं ( faqs.org/rfcs/rfc793.html ) धारा 3.5 एक कनेक्शन बंद करना। मुझे यकीन नहीं है कि यह इस मुद्दे की व्याख्या करता है, क्योंकि दोनों पक्ष कनेक्शन के सुंदर बंद को पूरा करते हैं और उन राज्यों में समाप्त होते हैं जहां उन्हें अपना डेटा नहीं भेजना / प्राप्त करना चाहिए।
अलेक्जेंडर

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

1
नहीं, दुर्भाग्य से ऐसा नहीं है। isOutputShutdown और isInputShutdown इस "खोज" के साथ सामना करने पर हर कोई पहली कोशिश करता है, लेकिन दोनों ही तरीके झूठे हैं। मैंने अभी इसे Windows XP और Linux 2.6 पर परीक्षण किया है। सभी 4 तरीकों का रिटर्न मान एक पढ़ी हुई कोशिश के बाद भी वही रहता है
अलेक्जेंडर

1
रिकॉर्ड के लिए, यह आधा-द्वैध नहीं है। हाफ-डुप्लेक्स का मतलब है कि केवल एक ही पक्ष s समय पर भेज सकता है; दोनों पक्ष अभी भी भेज सकते हैं।
आरबीपी

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

3

यह जावा (और अन्य सभी का दोष है) जिसे मैंने देखा है) OO सॉकेट क्लासेस - सिलेक्ट सिस्टम कॉल का एक्सेस नहीं है।

C में सही उत्तर:

struct timeval tp;  
fd_set in;  
fd_set out;  
fd_set err;  

FD_ZERO (in);  
FD_ZERO (out);  
FD_ZERO (err);  

FD_SET(socket_handle, err);  

tp.tv_sec = 0; /* or however long you want to wait */  
tp.tv_usec = 0;  
select(socket_handle + 1, in, out, err, &tp);  

if (FD_ISSET(socket_handle, err) {  
   /* handle closed socket */  
}  

आप एक ही काम कर सकते हैं getsocketop(... SOL_SOCKET, SO_ERROR, ...)
डेविड श्वार्ट्ज

1
त्रुटि फ़ाइल डिस्क्रिप्टर सेट बंद कनेक्शन को इंगित नहीं करेगा। कृपया चयनित मैनुअल पढ़ें: 'अपवर्जित - यह सेट "असाधारण स्थितियों" के लिए देखा जाता है। व्यवहार में, केवल एक ही ऐसी उत्कृष्ट स्थिति आम है: टीसीपी सॉकेट से पढ़ने के लिए आउट-ऑफ-बैंड (ओओबी) डेटा की उपलब्धता। ' फिन OOB डेटा नहीं है।
जन विद्रोह

1
'चयनकर्ता ()' syscall का उपयोग करने के लिए आप 'चयनकर्ता' वर्ग का उपयोग कर सकते हैं। हालांकि यह NIO का उपयोग करता है।
Matthieu

1
एक कनेक्शन के बारे में कुछ भी असाधारण नहीं है जो दूसरी तरफ से बंद हो गया है।
डेविड श्वार्ट्ज

1
कई प्लेटफार्मों, सहित जावा, कर का चयन करें () सिस्टम कॉल के लिए उपयोग प्रदान करते हैं।
लोर्ने

2

यहाँ एक लंगड़ा वर्कअराउंड है। SSL का उपयोग करें;) और एसएसएल फाड़ पर एक बंद हैंडशेक करता है, इसलिए आपको सॉकेट बंद होने की सूचना दी जाती है (ज्यादातर कार्यान्वयन एक उचित हैंडशेक फाड़ है जो लगता है)।


2
जावा में एसएसएल का उपयोग करते समय किसी को सॉकेट के "अधिसूचित" कैसे किया जाता है?
डेव बी

2

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

अधिक जानकारी के लिए यूनिक्स सॉकेट FAQ देखें


2
REALbasic सॉकेट (Mac OS X और Linux पर) BSD सॉकेट पर आधारित हैं, फिर भी RB आपको एक अच्छा त्रुटि 102 देता है जब कनेक्शन दूसरे छोर से गिरा दिया जाता है। इसलिए मैं मूल पोस्टर से सहमत हूं, यह संभव होना चाहिए और यह लंगड़ा है कि जावा (और कोको) इसे प्रदान नहीं करते हैं।
जो स्ट्रैट

1
@JoeStrout RB केवल तभी कर सकते हैं जब आप कुछ I / O करते हैं। कोई एपीआई नहीं है जो आपको I / O किए बिना कनेक्शन की स्थिति देगा। अवधि। यह जावा की कमी नहीं है। यह वास्तव में टीसीपी में एक 'डायल टोन' की कमी के कारण है, जो एक जानबूझकर डिजाइन विशेषता है।
२०:२० पर लोर्ने

select() आपको बताता है कि क्या कोई डेटा या ईओएस उपलब्ध है जिसे बिना ब्लॉक किए पढ़ा जा सकता है। 'ऐसे संकेत जिन्हें आप अवरुद्ध किए बिना आज़मा सकते हैं' अर्थहीन है। यदि आप नॉन-ब्लॉकिंग मोड में हैं, तो आप हमेशा बिना ब्लॉक किए प्रयास कर सकते हैंselect()सॉकेट में डेटा द्वारा संचालित होता है बफर प्राप्त करें या सॉकेट भेजें में एक लंबित फिन या स्थान प्राप्त करें।
२०:१६ को लोर्ने का

@EJP के बारे में क्या getsockopt(SO_ERROR)? वास्तव में, यहां तक getpeernameकि आपको बताएगा कि क्या सॉकेट अभी भी जुड़ा हुआ है।
डेविड श्वार्ट्ज

0

केवल लिखते हैं कि पैकेट का आदान-प्रदान किया जाना चाहिए जो कनेक्शन के नुकसान को निर्धारित करने की अनुमति देता है। चारों ओर एक आम काम KEEP ALIVE विकल्प का उपयोग करना है।


मुझे लगता है कि किसी भी पेलोड को लिखे बिना, एक समापन बिंदु को फिन सेट के साथ एक पैकेट भेजकर एक सुंदर कनेक्शन बंद करने की अनुमति दी जाती है।
अलेक्जेंडर

@Alexander बेशक यह करता है, लेकिन यह इस जवाब के लिए प्रासंगिक नहीं है, जो कनेक्शन के कम का पता लगाने के बारे में है।
लोर्न

-3

जब यह आधे-खुले जावा सॉकेट्स के साथ काम करने की बात आती है, तो कोई इस पर नज़र डाल सकता है कि IsputShutdown () और isOutputShutdown () है


नहीं। यह केवल आपको बताता है कि आपने क्या कहा है, न कि सहकर्मी ने जो फोन किया है।
लोरेन

उस वक्तव्य के लिए अपने स्रोत को साझा करने की देखभाल करें?
जिमीबीस

3
विपरीत के लिए अपने स्रोत को साझा करने की देखभाल? यह आपका कथन है। अगर आपके पास कोई सबूत है, तो आइए। मैं दावा करता हूं कि आप गलत हैं। प्रयोग करो और मुझे गलत साबित करो।
लोरेन

तीन साल बाद और कोई प्रयोग नहीं। QED
लोर्न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.