2008-10-15 19 views
7

在編寫一些測試代碼時,我發現Selector.select()可以在沒有包含任何要處理的鍵的Selector.selectedKeys()的情況下返回。這是在一個緊密的循環,當我註冊Java NIO select()返回沒有選定的鍵 - 爲什麼?

SelectionKey.OP_READ | SelectionKey.OP_CONNECT

爲感興趣的操作的接受()的通道發生。

根據該文件,選擇()應該返回時:

1)是可以被作用的通道。

2)您顯式調用Selector.wakeup() - 不選擇任何鍵。 3)你顯式地使用了Thread.interrupt()方法來執行select() - 沒有鍵被選中。如果在select()之後我沒有得到任何鍵,我必須在case(2)和(3)的情況下。但是,我的代碼並沒有調用wakeup()或interrupt()來啓動這些返回。

任何想法是什麼導致這種行爲?

回答

9

簡答題:從您對接受的連接感興趣的操作列表中刪除OP_CONNECT - 接受的連接已經連接。

我設法重現的問題,這可能正是發生了什麼你:上述服務器接收到一個連接,非常的連接退出第一select()後不會阻塞

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()); 
    } 
} 

,也沒有鑰匙隨時準備運營。我不知道爲什麼Java會以這種方式行事,但似乎很多人都被這種行爲所困擾。

結果與Windows XP上Sun的JVM 1.5.0_06以及Linux 2.6上Sun的JVM 1.5.0_05和1.4.2_04相同。

+0

感謝您的回答。這顯然是select的行爲中的一個反常現象,但它很容易解決。 – 2008-11-06 09:55:54

9

的原因是OP_CONNECTOP_WRITE是引擎蓋下同樣的事情,所以你永遠不應該被註冊爲兩者同時進行(同上OP_ACCEPTOP_READ),和你永遠不應該被註冊爲OP_CONNECT在所有的時候通道已經如同在這種情況下一樣,已被接受。

OP_WRITE幾乎總是準備好的,除非e內核中的套接字發送緩衝區已滿,所以您應該只在得到零長度寫入後註冊。所以通過註冊已經連接的頻道OP_CONNECT,你真的註冊了OP_WRITE,已經準備好了,所以select()被觸發了。

相關問題