使用 Selector 等待事件(例如使用 OP CONNECT)
NIO 出現在 Java 1.4 中並引入了 Channels
的概念,它應該比常規 I / O 更快。在網路方面, SelectableChannel
是最有趣的,因為它允許監視訊道的不同狀態。它的工作方式與 C select()
系統呼叫類似:當發生某些型別的事件時,我們會被喚醒:
- 接收連線(
OP_ACCEPT
) - 連線實現(
OP_CONNECT
) - 讀 FIFO 中可用的資料(
OP_READ
) - 可以推送資料寫入 FIFO(
OP_WRITE
)
它允許在檢測插槽 I / O(可以讀/寫/ …)和執行 I / O(讀/寫/ …)之間分離。特別是,所有 I / O 檢測都可以在一個執行緒中為多個套接字(客戶端)完成,而執行 I / O 可以線上程池或其他任何地方進行處理。這允許應用程式容易地擴充套件到連線的客戶端的數量。
以下示例顯示了基礎知識:
- 建立一個
Selector
- 建立一個
SocketChannel
- 註冊
SocketChannel
到Selector
- 使用
Selector
迴圈檢測事件
Selector sel = Selector.open(); // Create the Selector
SocketChannel sc = SocketChannel.open(); // Create a SocketChannel
sc.configureBlocking(false); // ... non blocking
sc.setOption(StandardSocketOptions.SO_KEEPALIVE, true); // ... set some options
// Register the Channel to the Selector for wake-up on CONNECT event and use some description as an attachement
sc.register(sel, SelectionKey.OP_CONNECT, "Connection to google.com"); // Returns a SelectionKey: the association between the SocketChannel and the Selector
System.out.println("Initiating connection");
if (sc.connect(new InetSocketAddress("www.google.com", 80)))
System.out.println("Connected"); // Connected right-away: nothing else to do
else {
boolean exit = false;
while (!exit) {
if (sel.select(100) == 0) // Did something happen on some registered Channels during the last 100ms?
continue; // No, wait some more
// Something happened...
Set<SelectionKey> keys = sel.selectedKeys(); // List of SelectionKeys on which some registered operation was triggered
for (SelectionKey k : keys) {
System.out.println("Checking "+k.attachment());
if (k.isConnectable()) { // CONNECT event
System.out.print("Connected through select() on "+k.channel()+" -> ");
if (sc.finishConnect()) { // Finish connection process
System.out.println("done!");
k.interestOps(k.interestOps() & ~SelectionKey.OP_CONNECT); // We are already connected: remove interest in CONNECT event
exit = true;
} else
System.out.println("unfinished...");
}
// TODO: else if (k.isReadable()) { ...
}
keys.clear(); // Have to clear the selected keys set once processed!
}
}
System.out.print("Disconnecting ... ");
sc.shutdownOutput(); // Initiate graceful disconnection
// TODO: emtpy receive buffer
sc.close();
System.out.println("done");
會給出以下輸出:
Initiating connection
Checking Connection to google.com
Connected through 'select()' on java.nio.channels.SocketChannel[connection-pending remote=www.google.com/216.58.208.228:80] -> done!
Disconnecting ... done