Android開發進階之NIO非阻塞包(三)
在Java的NIO中,ServerSocketChannel對應的是傳統IO中的ServerSocket,通過ServerSocketChannel類的socket() 方法可以獲得一個傳統的ServerSocket物件,同時從ServerSocket物件的getChannel() 方法,可以獲得一個ServerSocketChannel()物件,這點說明NIO的ServerSocketChannel和傳統IO的ServerSocket是有關聯的,例項化ServerSocketChannel 只需要直接呼叫ServerSocketChannel 類的靜態方法open()即可。
二、 SocketChannel 套接字通道 java.nio.channels.SocketChannel
在Java的New I/O中,處理Socket類對應的東西,我們可以看做是SocketChannel,套接字通道關聯了一個Socket類,這一點使用SocketChannel類的socket() 方法可以返回一個傳統IO的Socket類。SocketChannel()物件在Server中一般通過Socket類的getChannel()方法獲得。
三、SelectionKey 選擇鍵 java.nio.channels.SelectionKey
在NIO中SelectionKey和Selector是最關鍵的地方,SelectionKey類中描述了NIO中比較重要的事件,比如OP_ACCEPT(用於伺服器端)、OP_CONNECT(用於客戶端)、OP_READ和OP_WRITE。
四、Selector 選擇器 java.nio.channels.Selector
在NIO中註冊各種事件的方法主要使用Selector來實現的,構造一個Selector物件,使用Selector類的靜態方法open()來例項化。
對於Android平臺上我們實現一個非阻塞的伺服器,過程如下:
1. 通過Selector類的open()靜態方法例項化一個Selector物件。
2. 通過ServerSocketChannel類的open()靜態方法例項化一個ServerSocketChannel物件。
3. 顯示的呼叫ServerSocketChannel物件的configureBlocking(false);方法,設定為非阻塞模式,Android123提示網友這一步十分重要。
4. 使用ServerSocketChannel物件的socket()方法返回一個ServerSocket物件,使用ServerSocket物件的bind()方法繫結一個IP地址和埠號
5. 呼叫ServerSocketChannel物件的register方法註冊感興趣的網路事件,很多開發者可能發現Android SDK文件中沒有看到register方法,這裡Android開發網給大家一個ServerSocketChannel類的繼承關係
java.lang.Object
↳ java.nio.channels.spi.AbstractInterruptibleChannel
↳ java.nio.channels.SelectableChannel
↳ java.nio.channels.spi.AbstractSelectableChannel
↳ java.nio.channels.ServerSocketChannel
這裡我們使用的register方法其實來自ServerSocketChannel的父類java.nio.channels.SelectableChannel,該方法原型為 final SelectionKey register(Selector selector, int operations) ,引數為我們執行第1步時的selector物件,引數二為需要註冊的事件,作為伺服器,我們當然是接受客戶端發來的請求,所以這裡使用SelectionKey.OP_ACCEPT了。
6. 通過Selector物件的select() 方法判斷是否有我們感興趣的事件發生,這裡就是OP_ACCEPT事件了。我們通過一個死迴圈獲取Selector物件執行select()方法的值,SDK中的原始描述為the number of channels that are ready for operation.,就是到底有多少個通道返回。
7. 如果 Selector物件的select()方法返回的結果數大於0,則通過selector物件的selectedKeys()方法獲取一個SelectionKey型別的Set集合,我們使用Java的迭代器Iterator類來遍歷這個Set集合,注意判斷SelectionKey物件,
8. 為了表示我們處理了SelectionKey物件,需要先移除這個SelectionKey物件從Set集合中。這句很關鍵Android 123提醒網友注意這個地方。
9. 接下來判斷SelectionKey物件的事件,因為我們註冊的感興趣的是SelectionKey.OP_ACCEPT事件,我們使用SelectionKey物件的isAcceptable()方法判斷,如果是我們建立一個臨時SocketChannel物件類似上面的方法繼續處理,不過這時這個SocketChannel物件主要處理讀寫操作,我們註冊SelectionKey.OP_READ和SelectionKey.OP_WRITE分配ByteBuffer緩衝區,進行網路資料傳輸。