2013-02-07 10 views
6

मेरे पास एक साधारण ग्राहक/सर्वर ऐप है। सर्वर स्थापित किया गया है ताकि यदि एन सेकंड के भीतर कोई डेटा नहीं आता है तो टाइमआउट होता है और सॉकेट कनेक्शन बंद हो जाता है। मैं इसे Socket.setSoTimeout() के माध्यम से करता हूं। क्लाइंट लटकता है तो यह सब ठीक काम करता है। यदि ग्राहक मर जाते हैं, हालांकि (उदा। मैं इसे Ctrl-C से मारता हूं), तो readLine() कभी भी कभी नहीं निकलता है।जावा में, एक बंद सॉकेट कनेक्शन पर readLine() ब्लॉक क्यों करता है?

यहाँ, सर्वर कोड है कि यदि एक फर्क नहीं पड़ता:

public void run() 
{ 
    PrintWriter out = null; 
    BufferedReader in = null; 

    try { 
     sock.setSoTimeout(10000); 

     out = new PrintWriter(sock.getOutputStream(), true); 
     in = new BufferedReader(new InputStreamReader(sock.getInputStream())); 

     String input; 
     while ((input = in.readLine()) != null) { 

मैं ग्राहक में एक संकेत हैंडलर में डाल सर्वर से एक Abend संदेश पर भेजने के लिए कोशिश की है लेकिन यह है कि काम नहीं कर रहा (मुझे लगता है ABEND भेजा जाने से पहले सॉकेट बंद हो जाता है, लेकिन मैंने इसे समझने की कोशिश करने में किसी भी समय वास्तव में खर्च नहीं किया है)।

क्या समय-समय पर जागने का तरीका है और यह देखने के लिए सॉकेट स्थिति की जांच करें कि यह बंद है या नहीं? या (बेहतर अभी तक) पढ़ा नहीं है लाइन() सॉकेट बंद होने पर लटका? क्या मुझे किसी प्रकार के अनबफर पाठक का उपयोग करना चाहिए? क्या एक unbuffered पाठक एक readLine जैसी तंत्र का समर्थन कर रहा है?

मैं लिनक्स पर जावा 6 का उपयोग कर रहा हूं।

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

+0

देखें http://stackoverflow.com/questions/1577719/java-sockets-bufferedreader-and-readline-hang - शायद सीआर भेजा गया था और पढ़ने के बाद क्लाइंट की मौत हो गई() कभी भी एलएफ का उपभोग नहीं किया गया, इस प्रकार यह इसके लिए तैयार है हमेशा के लिए – mantrid

+0

मैं एक निष्क्रिय अवधि के दौरान खुद को क्लाइंट की हत्या कर रहा हूं; इस बिंदु पर सभी डेटा भेजा और प्राप्त किया गया है। –

+0

किस प्रकार की सॉकेट? टीसीपी या यूडीपी? – ecbrodie

उत्तर

1

मुझे लगता है कि आपने समस्या का गलत निदान किया है।

यदि सॉकेट का इनपुट पक्ष बंद कर दिया गया है, तो readLine() कॉल को बंद करना चाहिए। सभी बफर किए गए डेटा का उपभोग करने के बाद, कॉल को null वापस करना चाहिए। (यदि सॉकेट सामान्य रूप से बंद हो जाता है, तो आपको IOException नहीं मिलेगा, लेकिन कनेक्शन कनेक्शन का समय हो सकता है ... उदाहरण के लिए।)

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


इनमें से कोई भी समाधान नहीं है, लेकिन मैं पूर्णता के लिए उत्तर दूंगा।

क्या समय-समय पर जागने का तरीका है और यह देखने के लिए सॉकेट स्थिति की जांच करें कि यह बंद है या नहीं?

एक और धागा ऐसा कर सकता है, लेकिन यह नहीं।

या (बेहतर अभी तक) पढ़ने के लिए नहीं है() सॉकेट बंद होने पर लटका है?

ऐसा होने वाला है।

क्या मुझे किसी प्रकार का एक अनबफर पाठक का उपयोग करना चाहिए?

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

क्या एक अनन्य पाठक एक रीडलाइन-जैसी तंत्र का समर्थन करता है?

नहीं, ऐसा नहीं है। ऊपर देखो।

+0

"सबसे स्पष्ट स्पष्टीकरण यह है कि सॉकेट अभी तक बंद नहीं हुआ है।" - क्लाइंट प्रोग्राम अब नहीं चल रहा है; जावा प्रक्रिया को मार दिया गया है। नेटस्टैट का उपयोग करके मैं देख सकता हूं कि सॉकेट वास्तव में बंद होता है, दोनों सिरों पर, फिर भी पढ़ा जाता है() अभी भी लटकता है। मैं इस जानकारी को ऊपर जोड़ दूंगा। –

+0

क्या आप इसके लिए एसएससीसीई प्रदान कर सकते हैं? http://sscce.org आप जो रिपोर्ट कर रहे हैं वह मेरे अनुभव का मुकाबला करता है ... –

+0

नीचे * काम * कोड देखें। मदद के लिए धन्यवाद, अपना समय बर्बाद करने के लिए खेद है। –

0

Javadoc के अनुसार, readLine() विधि एक IOException फेंक देगा। और IOException के Javadoc के अनुसार, अपवाद को एक बाधा पर फेंकने की उम्मीद है। कोड लिखने के बिना, मैं कहूंगा कि आप IOException को पकड़कर समय-समय पर बंद होने वाले स्ट्रीम के मामले को संभाल सकते हैं।

+0

समस्या यह है कि, बाधा कभी नहीं फेंक दी जाती है। –

1

क्या आप इससे नफरत करते हैं जब आप ऐसी समस्या का पीछा करने में घंटों खर्च करते हैं जो वहां नहीं है? स्टीफन सी के लिए एसएससीसीई प्रदान करने के मेरे प्रयास में मैंने पाया कि मैं ऐसा उदाहरण प्रदान नहीं कर सका क्योंकि यह काम कर रहा है।

sscceServer.java

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.InetAddress; 
import java.net.ServerSocket; 
import java.net.Socket; 


public class sscceServer 
{ 
    public static class EchoHandlerThread implements Runnable 
    { 
     private final Socket sock; 
     private final int id; 

     public EchoHandlerThread(Socket s, int i) 
     { 
      sock = s; 
      id = i; 
     } 

     public void run() 
     { 
      try { 
       //----- set socket read timeout to 10 seconds ----- 
       sock.setSoTimeout(10000); 

       PrintWriter out = new PrintWriter(sock.getOutputStream(), true); 
       BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); 

       String input; 
       while ((input = in.readLine()) != null) { 
        System.out.println("[" + id + "] <" + input + ">"); 
       } 

       out.close(); 
       in.close(); 
       sock.close(); 

       System.out.println("\tConnection #" + id + " closed"); 
      } 
      catch (Exception ex) { 
       throw new RuntimeException(ex); 
      } 
     } 
    } 

    public static class Listener 
    { 
     private final InetAddress bindip; 
     private final int portnum; 

     public Listener(String ipstr, int pn) 
     { 
      try { 
       bindip = InetAddress.getByName(ipstr); 
       portnum = pn; 
      } 
      catch (Exception ex) { 
       throw new RuntimeException(ex); 
      } 
     } 

     public void start() 
     { 
      try { 
       ServerSocket srvsock = new ServerSocket(portnum, 0, bindip); 
       System.out.println("Listening on " + bindip.getHostAddress() + ":" + portnum); 

       int connum = 0; 
       while (true) { 
        Socket sock = srvsock.accept(); 

        connum++; 
        InetAddress ipaddr = sock.getInetAddress(); 
        System.out.println("Connection #" + connum + " from: " + ipaddr.getHostAddress()); 

        new Thread(new EchoHandlerThread(sock, connum)).start(); 
       } 
      } 
      catch (Exception ex) { 
       throw new RuntimeException(ex); 
      } 
     } 
    } 


    public static void main(String[] args) 
    { 
     Listener lsnr = new Listener("localhost", 8988); 
     lsnr.start(); 
    } 
} 

: मेरी डिबग कोड मुद्दा ...

बनाने गया था रिकॉर्ड के लिए, यहाँ कोड काम कर रहा है (किसी और मामले किसी में एक ऐसी ही समस्या है) sscceClient.java

import java.io.BufferedReader; 
import java.io.InputStreamReader; 
import java.io.PrintWriter; 
import java.net.Socket; 

public final class sscceClient 
{ 
    public static void main(String[] args) 
    { 
     try { 
      Socket sock = new Socket("localhost", 8909); 

      PrintWriter out = new PrintWriter(sock.getOutputStream(), true); 
      BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream())); 

      out.println("Lorem ipsum dolor sit amet, consectetur adipiscing elit."); 
      out.println("Ut sem ante, mollis ut porttitor at, aliquet vel nulla."); 
      out.println("Suspendisse quis sapien ante, a cursus nunc."); 

      //---- sleep for 20 seconds ----- 
      Thread.sleep(20000); 

      out.close(); 
      in.close(); 
      sock.close(); 
     } 
     catch (Exception ex) { 
      throw new RuntimeException(ex); 
     } 
    } 
} 

मदद के लिए धन्यवाद!

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