Class Reactor:
/**
*
* 經典的網絡服務在每個線程中完成對數據的處理:
* 但這種模式在用戶負載增加時,性能將下降非常的快。
* 系統運行的性能瓶頸通常在I/O讀寫,包括對端口和文件的操作上,過去,在打 開一個I/O通道後,
* read()將一直等待在端口一邊讀取字節內容,如果沒有內容進來,read()也是傻傻的等,
* 這會影響我們程序繼續做其他事情,那 麼改進做法就是開設線程,讓線程去等待,但是這樣做也是相當耗費資源(傳統socket通訊服務器設計模式) 的。
*
* Java NIO非堵塞技術實際是採取Reactor模式,或者說是Observer模式爲我們監察I/O端口,
* 如果有內容進來,會自動通知我們,這樣,我們就不必開啓多個線程死等,從外界看,實現了流暢的I/O讀寫,不堵塞了。
* NIO 有一個主要的類Selector,這個類似一個觀察者 ,只要我們把需要探知的 socketchannel告訴Selector,
* 我們接着做別的事情,當有事件發生時,他會通知我們,傳回一組SelectionKey,我們讀取這些 Key,就會獲得我們剛剛註冊過的socketchannel,
* 然後,我們從這個Channel中讀取數據,放心,包準能夠讀到,接着我們可以處理這些數據。
* Selector內部原理實際是在做一個對所註冊的channel的輪詢訪問 ,不斷的輪詢(目前就這一個算法),一旦輪詢到一個channel有所註冊的事情發生,
* 比如數據來了,他就會站起來報告,交出一把鑰匙,
* 讓我們通過這把鑰匙(SelectionKey 表示 SelectableChannel 在 Selector 中的註冊的標記。 )來讀取這個channel的內容。
*
* 反應器模式
* 用於解決多用戶訪問併發問題
* 舉個例子:餐廳服務問題
* 傳統線程池做法:來一個客人(請求)去一個服務員(線程)
* 反應器模式做法:當客人點菜的時候,服務員就可以去招呼其他客人了,等客人點好了菜,直接招呼一聲“服務員”
*/
public class Reactor implements Runnable{
//同步事件分離器,阻塞等待Handles中的事件發生
public final Selector selector;
public final ServerSocketChannel serverSocketChannel;
public Reactor(int port) throws IOException{
selector=Selector.open();
serverSocketChannel=ServerSocketChannel.open();
InetSocketAddress inetSocketAddress=new InetSocketAddress(InetAddress.getLocalHost(),port);
serverSocketChannel.socket().bind(inetSocketAddress);
/*
* ServerSocketChannel可以設置成非阻塞模式。
* 在非阻塞模式下,accept() 方法會立刻返回,如果還沒有新進來的連接,返回的將是null。
* 因此,需要檢查返回的SocketChannel是否是null.
*/
serverSocketChannel.configureBlocking(false);
/*
* 向selector註冊該serverSocketChannel
* SelectionKey.OP_ACCEPT —— 接收連接繼續事件,表示服務器監聽到了客戶連接,服務器可以接收這個連接了
* SelectionKey.OP_CONNECT —— 連接就緒事件,表示客戶與服務器的連接已經建立成功
* SelectionKey.OP_READ —— 讀就緒事件,表示通道中已經有了可讀的數據,可以執行讀操作了(通道目前有數據,可以進行讀操作了)
* SelectionKey.OP_WRITE —— 寫就緒事件,表示已經可以向通道寫數據了(通道目前可以用於寫操作)
* 這裏 注意,下面兩種,SelectionKey.OP_READ ,SelectionKey.OP_WRITE ,
* 1.當向通道中註冊SelectionKey.OP_READ事件後,如果客戶端有向緩存中write數據,下次輪詢時,則會 isReadable()=true;
* 2.當向通道中註冊SelectionKey.OP_WRITE事件後,這時你會發現當前輪詢線程中isWritable()一直爲ture,如果不設置爲其他事件
*/
SelectionKey selectionKey=serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
/*
* 利用selectionKey的attache功能綁定Acceptor 如果有事情,觸發Acceptor
* 該selectionKey爲serverSocketChannel的selectionKey
* attach的爲new Acceptor(this)
* 用於void dispatch(SelectionKey key)中獲取key.attachment()
* 將被本類中的run()方法的selectionKeys.clear(); 清空
* 第二次的selector.selectedKeys();獲取到的將會是socketChannel註冊的OP_READ的selectionKey(attach的爲SocketReadHandler)
*/
selectionKey.attach(new Acceptor(this));
}
@Override
public void run() {
try {
while(!Thread.interrupted()){
selector.select();
Set<SelectionKey> selectionKeys= selector.selectedKeys();
Iterator<SelectionKey> it=selectionKeys.iterator();
//Selector如果發現channel有OP_ACCEPT或READ事件發生,下列遍歷就會進行。
while(it.hasNext()){
SelectionKey selectionKey=it.next();
/*
* 第一次觸發此方法,獲取(OP_ACCEPT)selectionKey.attachment()爲new Acceptor(this)
* Acceptor run()方法裏面爲 new SocketReadHandler(reactor.selector, socketChannel);
* 在SocketReadHandler構造方法中將socketChannel register到Selector,返回selectionKey
* 再將該socketChannel的selectionKey attach(this); this represent new出來的SocketReadHandler
*
* 第二次觸發此方法,獲取(OP_READ)selectionKey.attachment()爲new出來的SocketReadHandler
* SocketReadHandler run()方法裏面爲 socketChannel.read(inputBuffer); 實際處理的邏輯代碼
*/
dispatch(selectionKey);
/*
* selectionKeys.clear(); 將selectionKeys清空,
* Acceptor類中的run()>>>new SocketReadHandler()構造方法中的 selector.wakeup()>>>再次觸發selector.select();
* Set<SelectionKey> selectionKeys= selector.selectedKeys();
* 第一次遍歷的selectionKeys裏面只有一個就是OP_ACCEPT的selectionKey,attachment爲Acceptor對象
* 第二次遍歷的selectionKeys裏面只有一個就是OP_READ的selectionKey,attachment爲SocketReadHandler對象
*/
selectionKeys.clear();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 運行Acceptor或SocketReadHandler
*/
void dispatch(SelectionKey key) {
//本例第一次此方法執行key爲serverSocketChannel註冊的selectionKey,key.attachment()爲Acceptor對象
//本例第二次此方法執行key爲socketChannel註冊的selectionKey,key.attachment()爲SocketReadHandler對象
Runnable r = (Runnable)(key.attachment());
if (r != null){
/*
* 第一次執行Acceptor的run(),run()方法將調用SocketReadHandler構造方法
* 在SocketReadHandler構造方法中將向selector註冊socketChannel,並attach(SocketReadHandler對象)
* 第二次執行SocketReadHandler的run(),處理具體邏輯代碼
*/
r.run();
}
}
}
Class Acceptor:
public class Acceptor implements Runnable{
private Reactor reactor;
public Acceptor(Reactor reactor){
this.reactor=reactor;
}
@Override
public void run() {
try {
/*
* ServerSocketChannel可以設置成非阻塞模式。
* 在非阻塞模式下,accept() 方法會立刻返回,如果還沒有新進來的連接,返回的將是null。
* 因此,需要檢查返回的SocketChannel是否是null.
*/
SocketChannel socketChannel=reactor.serverSocketChannel.accept();
/*
* 調用Handler來處理channel
* 在SocketReadHandler構造方法中將socketChannel register到Selector,返回selectionKey
* 再將該socketChannel的selectionKey attach(this); this represent new出來的SocketReadHandler
*/
if(socketChannel!=null) new SocketReadHandler(reactor.selector, socketChannel);
} catch (IOException e) {
e.printStackTrace();
}
}
}
Class SocketReadHandler :
public class SocketReadHandler implements Runnable{
private SocketChannel socketChannel;
public SocketReadHandler(Selector selector,
SocketChannel socketChannel) throws IOException{
this.socketChannel=socketChannel;
socketChannel.configureBlocking(false);
SelectionKey selectionKey=socketChannel.register(selector, 0);
//將該socketChannel註冊的SelectionKey綁定爲本SocketReadHandler
//下一步有事件觸發時,將調用本類的run方法。
//參看dispatch(SelectionKey key)
selectionKey.attach(this);
//同時將SelectionKey標記爲可讀,以便讀取。
selectionKey.interestOps(SelectionKey.OP_READ);
selector.wakeup();
}
/**
* 處理讀取數據
*/
@Override
public void run() {
ByteBuffer inputBuffer=ByteBuffer.allocate(1024);
inputBuffer.clear();
try {
socketChannel.read(inputBuffer);
//激活線程池 處理這些request
//requestHandle(new Request(socket,btt));
} catch (IOException e) {
e.printStackTrace();
}
}
}