package com.study.hc.net.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;
/**
* NIO selector 多路复用reactor线程模型
* /
Public class NIOServerV3 {
/ ** threading business operations * /
Private static ExecutorService workPool = Executors.newCachedThreadPool ();
/ **
* encapsulates the selector.select () like polling event code
* /
abstract class ReactorThread the extends {the Thread
Selector Selector;
a LinkedBlockingQueue <the Runnable> = taskqueue new new a LinkedBlockingQueue <> ();
/ **
* Selector monitored an event after calling this method
* /
public abstract void Handler (a SelectableChannel Channel) throwsException;
Private ReactorThread () throws IOException {
Selector = Selector.open ();
}
volatile Boolean running = to false ;
@Override
public void RUN () {
// polling event Selector
the while (running) {
the try {
// perform queue the task of
the Runnable task;
the while (! (task taskQueue.poll = ()) = null ) {
task.run ();
}
the selector.select ( 1000 );
// Get the query result
the Set <the SelectionKey> Selected = selector.selectedKeys ();
// iterate the query result
the Iterator <the SelectionKey> ITER = selected.iterator ();
the while (iter.hasNext ()) {
// encapsulated query results
SelectionKey Key = iter.next ();
iter.remove ();
int readyOps = key.readyOps ();
// attention Read and Accept two events
if(! (the readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) = 0 || the readyOps == 0 ) {
the try {
a SelectableChannel Channel = (a SelectableChannel) key.attachment ();
channel.configureBlocking ( to false );
Handler (Channel) ;
IF (! {channel.isOpen ())
key.cancel (); // if closed, to the unsubscribed KEY
}
} the catch (Exception EX) {
key.cancel ();// If an exception, to cancel the subscription KEY
}
}
}
selector.selectNow ();
} the catch (IOException E) {
e.printStackTrace ();
}
}
}
Private the SelectionKey Register (a SelectableChannel Channel) throws Exception {
// Why to register in the form of job submission, so that reactor thread to handle?
// thread because the thread performing channel selector in the process of registering to, and will call selector.select () method of the same lock contention
// The select () method call it cycle through while in eventLoop, the competition may high, in order to allow faster execution register, put it to deal with the same thread
FutureTask<SelectionKey> futureTask = new FutureTask<>(() -> channel.register(selector, 0, channel));
taskQueue.add(futureTask);
return futureTask.get();
}
private void doStart() {
if (!running) {
running = true;
start();
}
}
}
private ServerSocketChannel serverSocketChannel;
// 1、创建多个线程 - accept处理reactor线程 (accept线程)
private ReactorThread[] mainReactorThreads = newReactorThread [. 1 ];
// 2, create multiple threads - io thread processing reactor (I / O threads)
Private ReactorThread [] = subReactorThreads new new ReactorThread [. 8 ];
/ **
* initialize the thread group
* /
Private void newGroup, () throws IOException {
// create IO thread, handles the client after the connection of the IO write socketChannel
for ( int I = 0; I <subReactorThreads.length; I ++ ) {
subReactorThreads [I] = new new ReactorThread () {
@Override
public void Handler (SelectableChannel Channel) throws{IOException
// Work thread only handles IO process, not an event handling accept
SocketChannel CH = (SocketChannel) Channel;
ByteBuffer requestBuffer = ByteBuffer.allocate (1024 );
the while (ch.isOpen () && ch.read (requestBuffer) =! -1 ) {
// the length of connection, there is no need to manually read end data is determined (here make a simple determination: over 0 bytes is considered the end of the request)
IF (requestBuffer.position ()> 0) BREAK ;
}
IF (requestBuffer.position () == 0) return ; // If there is no data, the subsequent processing is not continued
requestBuffer.flip ();
byte [] Content = new new byte [requestBuffer.limit ()];
requestBuffer.get (Content);
System.out.println ( new new String (Content));
System.out.println (Thread.currentThread () .getName () + "receives data from:" + ch.getRemoteAddress ());
// the TODO operational databases, interfaces ...
workPool.submit (() -> {
});
// response result 200 is
String = Response "the HTTP / 1.1 200 is the OK \ R & lt \ n-" +
"the Content-the Length:. 11 \ R & lt \ n-\ R & lt \ n-" +
"the Hello World" ;
ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
while (buffer.hasRemaining()) {
ch.write(buffer);
}
}
};
}
// 创建mainReactor线程, 只负责处理serverSocketChannel
for (int i = 0; i < mainReactorThreads.length; i++) {
mainReactorThreads[i] = new ReactorThread() {
AtomicInteger incr = new AtomicInteger(0);
@Override
public void Handler (a SelectableChannel Channel) throws Exception {
// only request distribution, specific data is not read
a ServerSocketChannel CH = (a ServerSocketChannel) Channel;
the SocketChannel SocketChannel = ch.accept ();
socketChannel.configureBlocking ( to false );
// after notification of the connection establishment, distributed I / O thread continues to read data
int index = incr.getAndIncrement ()% subReactorThreads.length;
ReactorThread workEventLoop = subReactorThreads [index];
workEventLoop.doStart ();
the SelectionKey SelectionKey = workEventLoop.register (SocketChannel);
selectionKey.interestOps (SelectionKey.OP_READ);
System.out.println (Thread.currentThread () getName (). + "receive new connection:" + socketChannel.getRemoteAddress ());
}
};
}
}
/ **
* initialize the channel, and a binding thread eventLoop
*
* @throws IOException the IO exception
* /
Private void initAndRegister () throws exception {
// . 1, creating ServerSocketChannel
ServerSocketChannel = ServerSocketChannel.open ();
serverSocketChannel.configureBlocking(false);
// 2、 将serverSocketChannel注册到selector
int index = new Random().nextInt(mainReactorThreads.length);
mainReactorThreads[index].doStart();
SelectionKey selectionKey = mainReactorThreads[index].register(serverSocketChannel);
selectionKey.interestOps(SelectionKey.OP_ACCEPT);
}
/**
* 绑定端口
*
* @throws IOException IO异常
*/
private void bind() throws{IOException
// 1, formally bound port, external services
serverSocketChannel.bind ( new new InetSocketAddress (8080 ));
System.out.println ( "startup is complete, port 8080" );
}
public static void main (String [] args) throws Exception {
NIOServerV3 nioServerV3 = new new NIOServerV3 ();
nioServerV3.newGroup (); // 1, create main and sub two threads
nioServerV3.initAndRegister (); // 2, create serverSocketChannel, registered on the selector on mainReactor thread
nioServerV3.bind () ; // 3, port bindings for the serverSocketChannel
}
}