启动时
SocketAcceptor代码
服务启动时将ioHandler和acceptor绑定
IoHandler ioHandler = new DefaultIoHandler(this);
try {
if (null == bindIP) {
acceptor.bind(new InetSocketAddress(port), ioHandler);
bind的主要代码如下
synchronized (lock) {
//启动worker。注意只有一个worker线程
startupWorker();
//向注册queue中添加
registerQueue.add(request);
//让所有阻塞在selector上的请求立即返回
selector.wakeup();
}
try {
//一个countdownLatch 在worker中处理后会进行countdown
request.done.await();
} catch (InterruptedException e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
}
worker执行的代码如下
int nKeys = selector.select();
//从registerQueue中获取SocketChannel并将其注册到selector上
registerNew();
if (nKeys > 0) {
//下一节的内容
processSessions(selector.selectedKeys());
}
cancelKeys();
if (selector.keys().isEmpty()) {
synchronized (lock) {
if (selector.keys().isEmpty()
&& registerQueue.isEmpty()
&& cancelQueue.isEmpty()) {
worker = null;
try {
selector.close();
} catch (IOException e) {
ExceptionMonitor.getInstance()
.exceptionCaught(e);
} finally {
SocketAcceptor.this.selector = null;
}
break;
}
}
}
接受新连接时
每一个SocketAcceptor都持有一群SocketIoProcessor作为打工的小弟。
private final SocketIoProcessor[] ioProcessors;
private SocketIoProcessor nextProcessor() {
if (this.processorDistributor == Integer.MAX_VALUE) {
this.processorDistributor = Integer.MAX_VALUE % this.processorCount;
}
return ioProcessors[processorDistributor++ % processorCount];
}
在上面的processSessions会调用新其的org.apache.mina.transport.socket.nio.SocketIoProcessor#addNew来交给小弟这个连接。
void addNew(SocketSessionImpl session) throws IOException {
newSessions.add(session);
startupWorker();
}
每个小弟会为每一个session启动一个worker线程
worker的核心代码如下
int nKeys = selector.select(1000);
//从newSessions队列中拿到channel并注册到selector上
doAddNew();
doUpdateTrafficMask();
if (nKeys > 0) {
//处理数据接受事件
process(selector.selectedKeys());
}
doFlush();
doRemove();
notifyIdleness();
接受数据时
session.getFilterChain().fireMessageReceived(session, buf);
沿着AbstractIoFilterChain,一直调用到TailFilter,这时调用用户的DefaultIoHandler。
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) throws Exception {
try {
session.getHandler().messageReceived(session, message);
} finally {
ByteBufferUtil.releaseIfPossible(message);
}
}