public classNonblockingServer {/**处理客户端读写*/
privateSelectorThread[] selectorThreads;/**建立新连接*/
privateAcceptThread acceptThread;/**选择器*/
privateSelectNextSelectorThread nextSelectorThread;/**默认selectorThread数量*/
private static int defaultSelectorNum = 3;publicNonblockingServer() {this(defaultSelectorNum);
}public NonblockingServer(intselectorThreadNum) {if (selectorThreadNum < 1) {throw new IllegalArgumentException("SelectorThread线程数量不能低于1");
}
selectorThreads= newSelectorThread[selectorThreadNum];try{for (int i = 0; i < selectorThreads.length; i++) {
selectorThreads[i]= new SelectorThread("selector-thread-" +i);
}
acceptThread= new AcceptThread("accept-thread");
nextSelectorThread= newSelectNextSelectorThread(Arrays.asList(selectorThreads));
}catch(Exception e) {throw newRuntimeException(e);
}
}public void listen(String host, intport) {try{
acceptThread.listen(host, port);
}catch(IOException e) {throw newRuntimeException(e);
}
}/*** 处理连接事件,把新连接注册到一个SelectorThread上*/
class AcceptThread extendsThread {privateSelector selector;privateServerSocketChannel serverChannel;
AcceptThread(String name)throwsIOException {super(name);
selector=Selector.open();
}public void listen(String host, int port) throwsIOException {
serverChannel=ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
serverChannel.bind(newInetSocketAddress(host, port));this.start();
}
@Overridepublic voidrun() {while (!Thread.currentThread().isInterrupted()) {try{int select =selector.select();if (select == 0) {continue;
}
Set keys =selector.selectedKeys();
Iterator iterator =keys.iterator();while(iterator.hasNext()) {
SelectionKey key=iterator.next();
iterator.remove();if(key.isAcceptable()) {
handAccept();
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}private void handAccept() throwsIOException {
SocketChannel clientChannel=serverChannel.accept();
SelectorThread selectorThread=nextSelectorThread.nextThread();//懒加载
if (!selectorThread.isStart()) {
selectorThread.start();
}
selectorThread.register(clientChannel);
}
}/*** 处理客户端连接的读/写事件*/
class SelectorThread extendsThread {privateSelector selector;private BlockingQueuetasks;private volatile boolean start = false;
SelectorThread(String name)throwsIOException {super(name);
selector=Selector.open();
tasks= new LinkedBlockingQueue<>();
}
@Overridepublic voidrun() {while(start) {try{
selector.select();
handTask();
Set keys =selector.selectedKeys();
Iterator iterator =keys.iterator();while (start &&iterator.hasNext()) {
SelectionKey key=iterator.next();
iterator.remove();
SocketChannel channel=(SocketChannel) key.channel();if(key.isReadable()) {
handRead(channel);
}else if(key.isWritable()) {
handWrite(channel);
}
}
}catch(Exception e) {
e.printStackTrace();
}
}
}private voidhandTask() {
Runnable task;while (start && (task = tasks.poll()) != null) {
task.run();
}
}/*** 这里简单的把输出打印出来*/
private void handRead(SocketChannel channel) throwsIOException {
ByteBuffer buffer= ByteBuffer.allocate(1024);int read =channel.read(buffer);if (read == -1) {
System.out.println(channel.getRemoteAddress()+ " 断开连接");
channel.close();
}else{byte[] bytes = new byte[read];
buffer.flip();
buffer.get(bytes);
System.out.println(newString(bytes));
buffer.clear();
}
}private voidhandWrite(SocketChannel channel) {//nothing
}/*** 把新连接注册到本线程*/
public voidregister(SocketChannel clientChannel) {
submit(()->{try{
clientChannel.configureBlocking(false);
clientChannel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}catch(Exception e) {try{
clientChannel.close();
}catch(IOException ex) {
ex.printStackTrace();
}
}
});
selector.wakeup();
}public voidsubmit(Runnable task) {
tasks.offer(task);
}
@Overridepublic synchronized voidstart() {
start= true;super.start();
}public voidshutdown() {this.start = false;this.interrupt();
}public booleanisStart() {returnstart;
}
}static classSelectNextSelectorThread {private final Collection extends SelectorThread>threads;private Iterator extends SelectorThread>iterator;public SelectNextSelectorThread(Collectionthreads) {this.threads =threads;
iterator= this.threads.iterator();
}/*** 选择下一个SelectorThread,这里为轮询
*
*@returnSelectorThread*/
publicSelectorThread nextThread() {if (!iterator.hasNext()) {
iterator=threads.iterator();
}returniterator.next();
}
}
}