package io.mycat.net; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.StandardSocketOptions; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author wuzh */ public final class NIOAcceptor extends Thread { private static final Logger LOGGER = LoggerFactory.getLogger(NIOAcceptor.class); private final int port; private final Selector selector; private final ServerSocketChannel serverChannel; private final ConnectionFactory factory; private long acceptCount; private final NIOReactorPool reactorPool; public NIOAcceptor(String name, String bindIp, int port, ConnectionFactory factory, NIOReactorPool reactorPool) throws IOException { super.setName(name); this.port = port; this.selector = Selector.open(); this.serverChannel = ServerSocketChannel.open(); this.serverChannel.configureBlocking(false); /** 设置TCP属性 */ serverChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true); serverChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024 * 16 * 2); // backlog=100 serverChannel.bind(new InetSocketAddress(bindIp, port), 100); this.serverChannel.register(selector, SelectionKey.OP_ACCEPT); this.factory = factory; this.reactorPool = reactorPool; } public int getPort() { return port; } public long getAcceptCount() { return acceptCount; } @Override public void run() { final Selector selector = this.selector; for (;;) { ++acceptCount; try { selector.select(1000L); Set<SelectionKey> keys = selector.selectedKeys(); try { for (SelectionKey key : keys) { if (key.isValid() && key.isAcceptable()) { accept(); } else { key.cancel(); } } } finally { keys.clear(); } } catch (Throwable e) { LOGGER.warn(getName(), e); } } } /** * 接受新连接 */ private void accept() { SocketChannel channel = null; try { channel = serverChannel.accept(); channel.configureBlocking(false); Connection c = factory.make(channel); c.setDirection(Connection.Direction.in); c.setId(ConnectIdGenerator.getINSTNCE().getId()); InetSocketAddress remoteAddr = (InetSocketAddress) channel .getRemoteAddress(); c.setHost(remoteAddr.getHostString()); c.setPort(remoteAddr.getPort()); // 派发此连接到某个Reactor处理 NIOReactor reactor = reactorPool.getNextReactor(); reactor.postRegister(c); } catch (Throwable e) { closeChannel(channel); LOGGER.warn(getName(), e); } } private static void closeChannel(SocketChannel channel) { if (channel == null) { return; } Socket socket = channel.socket(); if (socket != null) { try { socket.close(); } catch (IOException e) { } } try { channel.close(); } catch (IOException e) { } } }