packagecom.dsp.nio;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importjava.io.IOException;importjava.net.InetSocketAddress;importjava.nio.channels.SelectionKey;importjava.nio.channels.Selector;importjava.nio.channels.ServerSocketChannel;importjava.nio.channels.SocketChannel;importjava.util.Iterator;importjava.util.Set;/***
* 监控是否可连接、可读、可写
*
* 代码中巧妙使用了SocketChannel的attach功能,将Hanlder和可能会发生事件的channel链接在一起,当发生事件时,可以立即触发相应链接的Handler
**/
public class Reactor implementsRunnable {private static Logger log = LoggerFactory.getLogger(Reactor.class);finalSelector selector;finalServerSocketChannel serverSocket;/*** 服务端配置初始化,监听端口
*@paramport
*@throwsIOException*/
public Reactor(int port) throwsIOException {this.selector =Selector.open();this.serverSocket =ServerSocketChannel.open();this.serverSocket.socket().bind(newInetSocketAddress(port));this.serverSocket.configureBlocking(false);
SelectionKey selectionKey= this.serverSocket.register(selector, SelectionKey.OP_ACCEPT);//利用selectionKey的attache功能绑定Acceptor 如果有事情,触发Acceptor
selectionKey.attach(newAcceptor());
log.info("===>>> attach(new Acceptor())");
}/** SPI*/
//Alternatively, use explicit SPI provider//SelectorProvider selectorProvider = SelectorProvider.provider();//selector = selectorProvider.openSelector();//serverSocket = selectorProvider.openServerSocketChannel();
/*** 分发请求
*
*@paramselectionKey*/
voiddispatch(SelectionKey selectionKey) {
Runnable run=(Runnable) (selectionKey.attachment());if (run != null) {
run.run();
}
}/*** 监听连接和channel是否就绪*/
public voidrun() {try{/*** 线程未被中断*/
while (!Thread.interrupted()) {int readySize = this.selector.select();
log.info("I/O ready size = {}", readySize);
Set> selectedKeys = this.selector.selectedKeys();
Iterator> iterator =selectedKeys.iterator();//Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。
while(iterator.hasNext()) {/** 一个新的连接,第一次出发Accepter线程任务,之后触发Handler线程任务*/SelectionKey selectionKey=(SelectionKey) iterator.next();
log.info("===>>> acceptable = {}, connectable = {}, readable = {}, writable = {}.",
selectionKey.isAcceptable(), selectionKey.isConnectable(),
selectionKey.isReadable(), selectionKey.isWritable());
dispatch(selectionKey);
}
selectedKeys.clear();
}
}catch(IOException ex) {
log.info("reactor stop!" +ex);
}
}/*** 处理新连接
*
*@authordsp
**/
class Acceptor implementsRunnable {
@Overridepublic voidrun() {try{
log.debug("===>>> ready for accept!");
SocketChannel socketChannel=serverSocket.accept();if (socketChannel != null) {newHandler(selector, socketChannel);
}
}catch(IOException ex) {/*. . .*/}
}
}
}