package com.github.luohaha.worker; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import com.github.luohaha.param.ServerParam; public class Accepter extends Worker implements Runnable { private ServerSocketChannel channel; private Selector selector; private ServerParam param; private List<IoWorker> workers = new ArrayList<>(); private int workerIndex = 0; public Accepter(ServerParam param) { this.selector = openSelector("[Accepter] open selector"); this.channel = openServerSocketChannelNonBlocking("[Accepter] open server socket channel"); this.param = param; bindAddress(this.channel, this.param); } /** * add worker thread * * @param worker * worker */ public void addIoWorker(IoWorker worker) { workers.add(worker); } public void accept() { registerChannel(); // select while (true) { try { this.selector.select(); Set<SelectionKey> keys = this.selector.selectedKeys(); Iterator<SelectionKey> iterator = keys.iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); handle(key); iterator.remove(); } } catch (IOException e) { this.logger.warning("[Accepter] select : " + e.toString()); this.selector = openSelector("[Accepter] select : "); registerChannel(); } } } private void handle(SelectionKey key) { if (key.isAcceptable()) { /* * accept */ ServerSocketChannel server = (ServerSocketChannel) key.channel(); try { SocketChannel channel = server.accept(); this.logger.info("[Accept] accept : " + channel.getRemoteAddress().toString()); IoWorker worker = workers.get(workerIndex); worker.dispatch(new JobBean(channel, this.param)); workerIndex = (workerIndex + 1) % workers.size(); } catch (IOException e) { // accepter error this.logger.warning("[Accept] accept : " + e.toString()); if (param.getOnAcceptError() != null) { param.getOnAcceptError().onAcceptError(e); } registerChannel(); } } } @Override public void run() { accept(); } /** * bind address * * @param serverSocketChannel * serverSocketChannel * @param serverParam * serverParam */ private void bindAddress(ServerSocketChannel serverSocketChannel, ServerParam serverParam) { do { try { serverSocketChannel.socket().bind(new InetSocketAddress(serverParam.getHost(), serverParam.getPort()), serverParam.getBacklog()); break; } catch (IOException e) { this.logger.warning("[Accepter] bind address : " + e.toString()); } } while (true); } /** * register */ private void registerChannel() { // register do { try { this.channel.register(this.selector, SelectionKey.OP_ACCEPT); break; } catch (ClosedChannelException e) { this.logger.warning("[Accepter] register : " + e.toString()); this.channel = openServerSocketChannelNonBlocking("[Accepter] open server socket channel "); bindAddress(this.channel, this.param); } } while (true); } }