2008-10-15 12 views
7

कुछ टेस्ट कोड लिखने में मैंने पाया है कि Selector.select() चयनकर्ता के बिना वापस आ सकता है। चयन किए गए कीज़() जिसमें प्रक्रिया के लिए कोई भी कुंजी है। यह एक तंग पाश में हो रहा है जब मैंजावा एनआईओ चयनित() चयनित कुंजी के बिना रिटर्न - क्यों?

SelectionKey.OP_READ | SelectionKey.OP_CONNECT
हित के संचालन के रूप में

के साथ एक को स्वीकार() एड चैनल रजिस्टर।)

1 चैनलों कि अपना काम कर सकती हैं:

डॉक्स के अनुसार, का चयन करें() जब वापस आ जाएगी।

2) आप स्पष्ट रूप से Selector.wakeup() को कॉल करते हैं - कोई कुंजी चयनित नहीं है।

3) आप स्पष्ट रूप से Thread.interrupt() थ्रेड चुनने वाले थ्रेड() - कोई कुंजी चयनित नहीं हैं।

यदि मुझे चयन के बाद कोई चाबियाँ नहीं मिलती हैं() मुझे मामलों (2) और (3) में होना चाहिए। हालांकि, मेरा कोड इन रिटर्न को शुरू करने के लिए wakeup() या इंटरप्ट() को कॉल नहीं कर रहा है।

इस व्यवहार के कारण क्या कोई विचार है?

उत्तर

9

संक्षिप्त उत्तर: स्वीकृत कनेक्शन के लिए रुचि रखने वाले संचालन की सूची से OP_CONNECT हटाएं - एक स्वीकृत कनेक्शन पहले से ही जुड़ा हुआ है।

मैं इस मुद्दे है, जो वास्तव में क्या आप के लिए क्या हो रहा है हो सकता है पुन: पेश करने में कामयाब रहे:

import java.net.*; 
import java.nio.channels.*; 


public class MyNioServer { 
    public static void main(String[] params) throws Exception { 
    final ServerSocketChannel serverChannel = ServerSocketChannel.open(); 
    serverChannel.configureBlocking(true); 
    serverChannel.socket().bind(new InetSocketAddress("localhost", 12345)); 
    System.out.println("Listening for incoming connections"); 
    final SocketChannel clientChannel = serverChannel.accept(); 
    System.out.println("Accepted connection: " + clientChannel); 


    final Selector selector = Selector.open(); 
    clientChannel.configureBlocking(false); 
    final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT); 
    System.out.println("Selecting..."); 
    System.out.println(selector.select()); 
    System.out.println(selector.selectedKeys().size()); 
    System.out.println(clientKey.readyOps()); 
    } 
} 

के बाद ऊपर सर्वर को रोके बिना एक कनेक्शन, बहुत पहले select() कनेक्शन रास्ते पर प्राप्त करता है और वहाँ कोई चाबियाँ हैं तैयार संचालन के साथ। मुझे नहीं पता कि जावा इस तरह से क्यों व्यवहार करता है, लेकिन ऐसा लगता है कि इस व्यवहार से कई लोग काटते हैं।

परिणाम विंडोज एक्सपी पर सूर्य के जेवीएम 1.5.0_06 के साथ ही सूर्य के जेवीएम 1.5.0_05 और 1.4.2_04 पर लिनक्स 2.6 पर समान है।

+0

उत्तर के लिए धन्यवाद। यह स्पष्ट रूप से चयन के व्यवहार में एक विसंगति है, लेकिन यह आसानी से सुलभ है। –

+0

@ फ्रैंकटाइलर मुझे नहीं पता कि प्रोग्रामिंग त्रुटि को 'चयन के व्यवहार में एक विसंगति' क्यों माना जाना चाहिए। – EJP

9

कारण यह है कि OP_CONNECT और OP_WRITE, हुड के नीचे एक ही बात कर रहे हैं तो आप दोनों एक साथ (डिट्टो OP_ACCEPT और OP_READ) के लिए कभी नहीं पंजीकृत किया जाना चाहिए है, और आप OP_CONNECT के लिए कभी नहीं पंजीकृत किया जाना चाहिए बिल्कुल जब चैनल पहले से ही है जुड़ा हुआ है, क्योंकि यह इस मामले में है, स्वीकार कर लिया गया है।

और OP_WRITE लगभग हमेशा तैयार है, सिवाय जब सॉकेट ई-कर्नेल में सॉकेट बफर भेजता है, तो आपको केवल शून्य लंबाई लिखने के बाद ही इसके लिए पंजीकरण करना चाहिए। तो OP_CONNECT, के लिए पहले से जुड़े चैनल को पंजीकृत करके आप वास्तव में OP_WRITE, के लिए पंजीकरण कर रहे थे जो तैयार था, इसलिए select() ट्रिगर हो गया।