NIO网络连接
1.启动入口
public void startNetEngine() throws Exception {
runTaskBeforeEngineStart();
startNetEngineByThreadPoolSizeInfo();
runTaskAfterEngineStart();
}
2.runTaskBeforeEngine与runTaskAfterEngine任务
(1)runTaskBeforeEngine:
- Service.addRunBeforeEngineStartTask(() -> Zdb.getInstance().start(meta));
(2)runTaskAfterEngineStart:
Engine.getProtocolScheduler().scheduleAtFixedRate(() -> load(path), 0,
period, TimeUnit.MILLISECONDS)() -> {
try {
final InetSocketAddress sa = new InetSocketAddress(httpServerIp, httpServerPort);
final HttpServer server = HttpServer.create(sa, 0);
server.setExecutor(ConcurrentEnvironment.getInstance().newThreadPool(“limax.auany.httpServer”,
httpServerPool));
httphandlers.forEach((context, handler) -> server.createContext(context, handler));
server.start();
Service.addRunBeforeEngineStopTask(() -> {
server.stop(0);
ConcurrentEnvironment.getInstance().shutdown(“limax.auany.httpServer”);
});
} catch (Exception e) {
if (Trace.isErrorEnabled())
Trace.error(“start httpServer”, e);
}
});() -> launchManagerTask(builder.dispatcher(new Dispatcher(Engine.getProtocolExecutor())),
GlobalIdListener.getInstance(), self.getAttribute(“name”))() -> launchManagerTask(
builder.dispatcher(new Dispatcher(Engine.getProtocolExecutor())), listener, name)() -> {
Thread thread = new Thread(() -> {
try {
limax.node.js.Main.launchEngine(module, parameters);
} catch (Exception e) {
if (Trace.isErrorEnabled())
Trace.error(“Load Node module: ” + module, e);
}
});
thread.setDaemon(true);
thread.start();
}
3.开启网络Engine.open
public static void open(int nioCpus, int netProcessors, int protocolSchedulers, int applicationExecutors) throws Exception {
if (netProcessors < 1 || protocolSchedulers < 1 || applicationExecutors < 1 || nioCpus < 1)
throw new IllegalArgumentException("any engine parameter must > 0");
lock.lock();
try {
if (!closed)
throw new IllegalStateException("engine is not closed!");
NetModel.initialize(new FixedCpuPoll(nioCpus), netProcessors);
ConcurrentEnvironment env = ConcurrentEnvironment.getInstance();
engineExecutor = new Dispatcher(env.newThreadPool("limax.net.Engine.applicationExecutor", 0));
applicationExecutor = env.newHashExecutor("limax.net.Engine.applicationExecutor", applicationExecutors);
protocolScheduler = env.newScheduledThreadPool("limax.net.Engine.protocolScheduler", protocolSchedulers);
protocolExecutor = env.newHashExecutor("limax.net.Engine.protocolScheduler", protocolSchedulers);
closed = false;
} finally {
lock.unlock();
}
}
NetModel包括FixedCapacityPoll和FixedCPUPoll两种策略,由NetModel.initialize初始化
public static void initialize(PollPolicy pp, int processPoolSize) throws IOException, JMXException {
ConcurrentEnvironment env = ConcurrentEnvironment.getInstance();
pollPolicy = pp;
env.newFixedThreadPool("limax.net.io.NetModel.processPool", processPoolSize);
processPool = env.newHashExecutor("limax.net.io.NetModel.processPool", processPoolSize * 16);
delayPool = env.newScheduledThreadPool("limax.net.io.NetModel.delayPool", delayPoolSize);
mbeans = MBeans.register(MBeans.root(), new TaskStateMXBean() {
public long getTotal() {
return NetTaskImpl.total.longValue();
}
public long getRunning() {
return NetTaskImpl.running.longValue();
}
public List<Integer> getPollTaskSize() {
return pollPolicy.q.stream().map(PollTask::size).collect(Collectors.toList());
}
}, "limax.net.io:type=NetModel,name=TaskState");
}
4.runTaskAfterEngineStart中会开启client,server网络连接
public static ServerContext addServer(SocketAddress sa, int backlog, int rsize, int wsize,
ServerContext.NetTaskConstructor constructor, boolean autoOpen) throws IOException {
ServerContextImpl context = new ServerContextImpl(sa, backlog, rsize, wsize, constructor);
if (autoOpen)
context.open();
return context;
}
public static void addClient(SocketAddress sa, NetTask task) throws IOException {
SocketChannel sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(sa);
pollPolicy.addChannel(sc, SelectionKey.OP_CONNECT, task);
}
其中ServerContextImpl.open()
public synchronized void open() throws IOException {
if (closed) {
channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().setReuseAddress(true);
channel.socket().bind(sa, backlog);
//注册Selector事件
NetModel.pollPolicy.addChannel(channel, SelectionKey.OP_ACCEPT, this);
closed = false;
}
}
5.PollTask中抽象了NIO连接过程
class PollTask implements Runnable, Comparable<PollTask> {
private final Selector sel;
private volatile boolean closed;
private volatile int size;
int size() {
return size;
}
@Override
public int compareTo(PollTask op) {
return size - op.size();
}
PollTask() throws IOException {
this.sel = Selector.open();
}
synchronized SelectionKey register(SelectableChannel ch, int ops, Object att) throws ClosedChannelException {
return ch.register(sel.wakeup(), ops, att);
}
void close() {
closed = true;
sel.wakeup();
}
private void doAccept(SelectionKey key) throws IOException {
ServerContextImpl context = (ServerContextImpl) key.attachment();
NetOperation op = context.newInstance();
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
channel.configureBlocking(false);
op.attachKey(NetModel.pollPolicy.addChannel(channel, 0, op));
}
private void doConnect(SelectionKey key) throws IOException {
NetOperation op = (NetOperation) key.attachment();
SocketChannel channel = (SocketChannel) key.channel();
if (!channel.finishConnect())
throw new IOException("impossibly, channel's socket is NOT connected");
op.attachKey(key.interestOps(0));
}
private void doRead(SelectionKey key) throws IOException {
NetOperation op = (NetOperation) key.attachment();
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer rbuf = op.getReaderBuffer();
synchronized (rbuf) {
if (channel.read(rbuf) == -1)
throw new IOException("the channel has reached end-of-stream");
if (!rbuf.hasRemaining()) {
key.interestOps(key.interestOps() & ~SelectionKey.OP_READ);
op.onReadBufferEmpty();
}
}
}
private void doWrite(SelectionKey key) throws IOException {
NetOperation op = (NetOperation) key.attachment();
SocketChannel channel = (SocketChannel) key.channel();
Queue<ByteBuffer> vbuf = op.getWriteBuffer();
synchronized (vbuf) {
op.bytesSent(channel.write(vbuf.toArray(new ByteBuffer[0])));
while (!vbuf.isEmpty() && !vbuf.peek().hasRemaining())
vbuf.poll();
if (vbuf.isEmpty()) {
if (op.isFinalInitialized()) {
op.setFinal();
throw new IOException("channel closed manually");
}
key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
op.onWriteBufferEmpty();
}
}
}
private void doClose(SelectionKey key, Throwable e) {
Object att = key.attachment();
if (att instanceof NetOperation)
((NetOperation) att).close(e);
else if (att instanceof ServerContextImpl)
try {
((ServerContextImpl) att).close();
} catch (IOException e1) {
}
}
//处理网络的线程池
@Override
public final void run() {
try {
synchronized (this) {
}
sel.selectedKeys().clear();
sel.select();
for (SelectionKey key : sel.selectedKeys()) {
try {
if (key.isAcceptable()) {
try {
doAccept(key);
} catch (Throwable e) {
}
} else if (key.isConnectable()) {
try {
doConnect(key);
} catch (Throwable e) {
doClose(key, e);
}
} else {
Throwable catched = null;
boolean needsche = false;
if (key.isReadable()) {
try {
doRead(key);
needsche = true;
} catch (Throwable e) {
catched = e;
}
}
if (key.isWritable()) {
try {
doWrite(key);
needsche = true;
} catch (Throwable e) {
if (catched == null)
catched = e;
}
}
if (catched != null)
doClose(key, catched);
else if (needsche)
((NetOperation) key.attachment()).schedule();
}
} catch (CancelledKeyException e) {
}
}
} catch (Throwable e) {
if (Trace.isDebugEnabled())
Trace.debug("limax.net.io.PollTask", e);
} finally {
if (closed) {
IOException e = new IOException("channel closed manually");
for (SelectionKey key : sel.keys())
doClose(key, e);
try {
sel.close();
} catch (IOException e1) {
}
} else {
size = sel.keys().size();
NetModel.pollPolicy.schedule(this);
}
}
}
}
6.总结:
(1)在接收消息时注册了StateTransportImpl,用于input,output coderc
(2)Engine.open()中配置了开启网络线程数
(3)网络,定时器,任务线程池包含:
engineExecutor = new Dispatcher(env.newThreadPool("limax.net.Engine.applicationExecutor", 0));
applicationExecutor = env.newHashExecutor("limax.net.Engine.applicationExecutor", applicationExecutors);
protocolScheduler = env.newScheduledThreadPool("limax.net.Engine.protocolScheduler", protocolSchedulers);
protocolExecutor = env.newHashExecutor("limax.net.Engine.protocolScheduler", protocolSchedulers);
(4)网络联通后下一个过程是网络协议的解析与加密问题