133 lines
3.1 KiB
Java
133 lines
3.1 KiB
Java
package ms.net;
|
|
|
|
import ms.Management;
|
|
|
|
import java.io.IOException;
|
|
import java.net.InetSocketAddress;
|
|
import java.nio.channels.SelectionKey;
|
|
import java.nio.channels.Selector;
|
|
import java.nio.channels.ServerSocketChannel;
|
|
import java.util.Iterator;
|
|
import java.util.concurrent.ExecutorService;
|
|
import java.util.concurrent.Executors;
|
|
|
|
/**
|
|
* Handles (NIO-based) networking events using the reactor pattern.
|
|
* @author Emperor
|
|
*/
|
|
public final class NioReactor implements Runnable {
|
|
|
|
/**
|
|
* The executor service.
|
|
*/
|
|
private final ExecutorService service;
|
|
|
|
/**
|
|
* The selector
|
|
*/
|
|
private Selector selector;
|
|
|
|
/**
|
|
* The socket channel.
|
|
*/
|
|
private ServerSocketChannel channel;
|
|
|
|
/**
|
|
* The I/O event handling instance.
|
|
*/
|
|
private final IoEventHandler eventHandler;
|
|
|
|
/**
|
|
* If the reactor is running.
|
|
*/
|
|
private boolean running;
|
|
|
|
/**
|
|
* Constructs a new {@code NioReactor}.
|
|
* @param poolSize The pool size.
|
|
*/
|
|
private NioReactor(int poolSize) {
|
|
this.service = Executors.newSingleThreadScheduledExecutor();
|
|
this.eventHandler = new IoEventHandler(Executors.newFixedThreadPool(poolSize));
|
|
}
|
|
|
|
/**
|
|
* Creates and configures a new {@code NioReactor} with a pool size of 1.
|
|
* @param port The port.
|
|
* @return The {@code NioReactor} {@code Object}.
|
|
* @throws IOException When an I/O exception occurs.
|
|
*/
|
|
public static NioReactor configure(int port) throws IOException {
|
|
return configure(port, 1);
|
|
}
|
|
|
|
/**
|
|
* Creates and configures a new {@code NioReactor}.
|
|
* @param port The port.
|
|
* @param poolSize The amount of threads in the thread pool.
|
|
* @return The {@code NioReactor} {@code Object}.
|
|
* @throws IOException When an I/O exception occurs.
|
|
*/
|
|
public static NioReactor configure(int port, int poolSize) throws IOException {
|
|
NioReactor reactor = new NioReactor(poolSize);
|
|
reactor.channel = ServerSocketChannel.open();
|
|
reactor.selector = Selector.open();
|
|
reactor.channel.bind(new InetSocketAddress(port));
|
|
reactor.channel.configureBlocking(false);
|
|
reactor.channel.register(reactor.selector, SelectionKey.OP_ACCEPT);
|
|
return reactor;
|
|
}
|
|
|
|
/**
|
|
* Starts the reactor.
|
|
*/
|
|
public void start() {
|
|
running = true;
|
|
service.execute(this);
|
|
}
|
|
|
|
@Override
|
|
public void run() {
|
|
while (running && Management.active) {
|
|
try {
|
|
if(selector.select() > 0){
|
|
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
|
|
while (keys.hasNext()) {
|
|
SelectionKey key = keys.next();
|
|
keys.remove();
|
|
try {
|
|
if (!key.isValid() || !key.channel().isOpen()) {
|
|
key.cancel();
|
|
continue;
|
|
}
|
|
if (key.isAcceptable()) {
|
|
eventHandler.accept(key, selector);
|
|
}
|
|
if (key.isReadable()) {
|
|
eventHandler.read(key);
|
|
}
|
|
else if (key.isWritable()) {
|
|
eventHandler.write(key);
|
|
}
|
|
} catch (Throwable t) {
|
|
eventHandler.disconnect(key, t);
|
|
}
|
|
}
|
|
} else {
|
|
System.out.println("SLEEPING");
|
|
Thread.sleep(200);
|
|
}
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Terminates the reactor (once it's done processing current I/O events).
|
|
*/
|
|
public void terminate() {
|
|
running = false;
|
|
}
|
|
|
|
} |