Java NIO框架Netty教程(六)
看到標題,您可能覺得,這跟Netty有什麼關係呢?確實,如果你完全是使用Netty的,那麼可能你可以完全不需要了解Selector。但是,不得不提的是,Netty底層關於NIO的實現也是基於Java的Selector的,是對Selector的封裝。所以,我個人認為理解好Selector對於使用和理解Netty都是很多有幫助的。當然,如果您確實不關心這些,只想會用Netty就可以了。那麼下文,您可以略過:)
我對於Selector也是新上手學習的。之前很多新人跟我交流,都會提到一個新框架或者一個新開源工具的使用和上手的問題。他們會覺得上手困難,耗費事件。不過筆者,從來沒有此種感覺。這裡正好,借用Selector
想要使用一個工具,自然是先了解其定位,解決問題的原理或者工作流程。所以,筆者先從網上了解了一下Selector大概的工作流程。
NIO 有一個主要的類Selector,這個類似一個觀察者,只要我們把需要探知的socketchannel告訴Selector,我們接著做別的事情,當有事件發生時,他會通知我們,傳回一組SelectionKey,我們讀取這些Key,就會獲得我們剛剛註冊過的socketchannel,然後,我們從這個Channel中讀取資料,放心,包準能夠讀到,接著我們可以處理這些資料。
上面那段文字是我摘錄的一小段總結,就這一小段基本已經可以說明問題了。接下來,我們要考慮的就是,要實現這個過程,我們需要做什麼?順著描述,我們可以想象,需要選擇器,需要訊息傳送的通道,需要註冊一個事件,用於識別。通道自然需要繫結到一個地址。有了這樣大概的想法,我們就可以去API裡找相關的介面。
Selector服務端樣例程式碼:
/**
* Java NIO Select模式服務端樣例程式碼
*
* @author lihzh
* @alia OneCoder
* @Blog http://www.coderli.com
* @date 2012-7-16 下午9:22:53
*/
public class NioSelectorServer {
/**
* @author lihzh
* @throws IOException
* @alia OneCoder
* @date 2012-7-16 下午9:22:53
*/
public static void main(String[] args) throws IOException {
// 建立一個selector選擇器
Selector selector = Selector.open();
// 開啟一個通道
ServerSocketChannel socketChannel = ServerSocketChannel.open();
// 繫結到9000埠
socketChannel.socket().bind(new InetSocketAddress(8000));
// 使設定non-blocking的方式。
socketChannel.configureBlocking(false);
// 向Selector註冊Channel及我們有興趣的事件
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
for (;;) {
// 選擇事件
selector.select();
// 當有客戶端準備連線到服務端時,便會出發請求
for (Iterator<SelectionKey> keyIter = selector.selectedKeys()
.iterator(); keyIter.hasNext();) {
SelectionKey key = keyIter.next();
keyIter.remove();
System.out.println(key.readyOps());
if (key.isAcceptable()) {
System.out.println("Accept");
// 接受連線到此Channel的連線
socketChannel.accept();
}
}
}
}
}
Selector客戶端樣例程式碼:
/**
* Java NIO Selector模式,客戶端程式碼
*
* @author lihzh
* @alia OneCoder
* @blog http://www.coderli.com
*/
public class NioSelectorClient {
/**
* @author lihzh
* @throws IOException
* @alia OneCoder
*/
public static void main(String[] args) throws IOException {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("127.0.0.1", 8000));
}
}
程式碼很簡單,服務端接受到客戶端的連線請求後,會打印出”Accept“資訊。
簡單概括就是,整一個通道,通道加個選擇過濾器,看來的事件是不是我想要的,不想要的乾脆不管,想要的,我就存起來,留著慢慢處理。
現在感覺是不是Netty確實跟這個機制比較像,如果讓你去實現Netty現有的功能,也有思路可想了吧。