2015-03-18 19 views
6

मुझे Scanner कक्षा के साथ एक बहुत ही अजीब समस्या का सामना करना पड़ रहा है। मैं एक विशेष ईओएफ टोकन के साथ Socket से संदेशों को पढ़ने के लिए Scanner का उपयोग कर रहा हूं। सबकुछ ठीक काम करता है अगर क्लाइंट एक बार में सभी अनुरोध लिखता है, या अनुरोधों के पास डेटा है, लेकिन अवरुद्ध hasNext() ऑपरेशन सर्वर पर लटकता है, और बदले में क्लाइंट, जब संदेशों में संदेश लिखा जाता है और अगला टोकन खाली स्ट्रिंग होना चाहिए ।java.util.Scanner हैनक्स्ट पर लटकता है()

इसका कारण क्या होगा? मैं इससे बचने के बारे में कैसे जा सकता हूं?

यहां मैं जो करने का प्रयास कर रहा हूं उसका एक सरलीकृत संस्करण है, \n परीक्षण उद्देश्यों के लिए उपयोग किया जा रहा है, मान लें कि डिलीमीटर कोई स्ट्रिंग हो सकता है।

सर्वर कोड:

ServerSocketChannel serverChannel = null; 
try { 
    serverChannel = ServerSocketChannel.open(); 

    ServerSocket serverSocket = serverChannel.socket(); 
    serverSocket.bind(new InetSocketAddress(9081)); 

    SocketChannel channel = serverChannel.accept(); 
    Socket socket = channel.socket(); 

    InputStream is = socket.getInputStream(); 
    Reader reader = new InputStreamReader(is); 
    Scanner scanner = new Scanner(reader); 
    scanner.useDelimiter("\n"); 

    OutputStream os = socket.getOutputStream(); 
    Writer writer = new OutputStreamWriter(os); 

    while (scanner.hasNext()) { 
     String msg = scanner.next(); 
     writer.write(msg); 
     writer.write('\n'); 
     writer.flush(); 
    } 
} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    if (serverChannel != null) { 
     try { 
      serverChannel.close(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

कार्य ग्राहक:

Socket socket = new Socket(); 
try { 
    socket.connect(new InetSocketAddress("localhost", 9081)); 

    InputStream is = socket.getInputStream(); 
    Reader reader = new InputStreamReader(is); 
    Scanner scanner = new Scanner(reader); 
    scanner.useDelimiter("\n"); 

    OutputStream os = socket.getOutputStream(); 
    Writer writer = new OutputStreamWriter(os); 

    writer.write("foo\n\nbar\n"); 
    writer.flush(); 
    System.out.println(scanner.next()); 
    System.out.println(scanner.next()); 
    System.out.println(scanner.next()); 

} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    try { 
     socket.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

फांसी ग्राहक:

Socket socket = new Socket(); 
try { 
    socket.connect(new InetSocketAddress("localhost", 9081)); 

    InputStream is = socket.getInputStream(); 
    Reader reader = new InputStreamReader(is); 
    Scanner scanner = new Scanner(reader); 
    scanner.useDelimiter("\n"); 

    OutputStream os = socket.getOutputStream(); 
    Writer writer = new OutputStreamWriter(os); 

    writer.write("foo\n"); 
    writer.flush(); 
    System.out.println(scanner.next()); 

    writer.write("\n"); 
    writer.flush(); 
    System.out.println(scanner.next()); 

    writer.write("bar\n"); 
    writer.flush(); 
    System.out.println(scanner.next()); 

} catch (IOException e) { 
    e.printStackTrace(); 
} finally { 
    try { 
     socket.close(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

उत्तर

0

आप स्वीकार कर लिया सॉकेट बंद करने नहीं कर रहे हैं।

आपको 'विशेष ईओएफ टोकन' की आवश्यकता नहीं है। धारा का अंत अस्पष्ट है।

+0

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

+0

कृपया याद रखें कि यह समस्या को पुन: उत्पन्न करने के लिए सिर्फ एक उदाहरण है, उत्पादन कोड वास्तव में गैर-अवरुद्ध सॉकेट चैनल का उपयोग करता है, लगातार कनेक्शन स्वीकार करता है, और सॉकेट के पढ़ने, लिखने और बंद करने के लिए कार्यकर्ता धागे को स्पॉन्स करता है। –

0

मैंने कोड का पता लगाने में कुछ समय बिताया और समस्या Scanner कक्षा में सबसे निश्चित रूप से एक दोष है।

public boolean hasNext() { 
    ensureOpen(); 
    saveState(); 
    while (!sourceClosed) { 
     if (hasTokenInBuffer()) 
      return revertState(true); 
     readInput(); 
    } 
    boolean result = hasTokenInBuffer(); 
    return revertState(result); 
} 

hasNext() कॉल hasTokenInBuffer()

private boolean hasTokenInBuffer() { 
    matchValid = false; 
    matcher.usePattern(delimPattern); 
    matcher.region(position, buf.limit()); 

    // Skip delims first 
    if (matcher.lookingAt()) 
     position = matcher.end(); 

    // If we are sitting at the end, no more tokens in buffer 
    if (position == buf.limit()) 
     return false; 

    return true; 
} 

hasTokenInBuffer() हमेशा पहले सीमांकक यदि वह मौजूद है के रूप में जावाडोक में विस्तार से बताया छोड़ देता है।

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

पहले हम टोकन है कि पिछले अनुरोध से बफर में अभी भी था को छोड़, तो हम नोटिस हम अपने बफर में किसी भी नए डेटा नहीं है तो हम readInput() कहते हैं, इस मामले में सिर्फ \n में है, तो हम पाश वापस hasTokenInBuffer() पर जो हमारे डेलीमीटर फिर से छोड़ देता है!

इस बिंदु पर सर्वर अधिक इनपुट की प्रतीक्षा कर रहा है, और ग्राहक प्रतिक्रिया के लिए प्रतीक्षा कर रहा है। गतिरोध।

यह आसानी से अगर हम पिछले टोकन को छोड़ दिया है, तो हम जांच से बचा जा सकता ...

private boolean skippedLast = false; 

private boolean hasTokenInBuffer() { 
    matchValid = false; 
    matcher.usePattern(delimPattern); 
    matcher.region(position, buf.limit()); 

    // Skip delims first 
    if (!skippedLast && matcher.lookingAt()) { 
     skippedLast = true; 
     position = matcher.end(); 
    } else { 
     skippedLast = false; 
    } 

    // If we are sitting at the end, no more tokens in buffer 
    if (position == buf.limit()) 
     return false; 

    return true; 
} 
संबंधित मुद्दे