Acceptor线程在等待新socket进入时,执行run()流程如下:
AbstractPollingIoAcceptor$Acceptor.processHandles(Iterator<H>)
AbstractPollingIoAcceptor$Acceptor.run()
NamePreservingRunnable.run()
ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker)
ThreadPoolExecutor$Worker.run()
Thread.run()
当有新socket连接时,关键代码如下:
AbstractPollingIoAcceptor$Acceptor.processHandles(Iterator<H>) 用来处理新socket.
private void processHandles(Iterator<H> handles) throws Exception
{
while (handles.hasNext())
{
H handle = handles.next();
handles.remove();
// Associates a new created connection to a processor,
// and get back a session
S session = accept(processor, handle); //生成新IoSession
//当有一个新socket链接时,返回一个IoSession
if (session == null)
{
continue;
}
initSession(session, null, null); //初始化IoSession
// add the session to the SocketIoProcessor
//当Acceptor发现新的socket,把socket和ioproces相关联。所有io事件由ioprocess处理
session.getProcessor().add(session);
}
}
private IoProcessor<S> getProcessor(S session)
{
IoProcessor<S> processor = (IoProcessor<S>) session.getAttribute(PROCESSOR);
if (processor == null) {
if (disposed || disposing) {
throw new IllegalStateException("A disposed processor cannot be accessed.");
}
//把processor和session相关联。根据session id和proceor pool 的大小来决定
processor = pool[Math.abs((int) session.getId()) % pool.length];
if (processor == null)
{
throw new IllegalStateException("A disposed processor cannot be accessed.");
}
session.setAttributeIfAbsent(PROCESSOR, processor);
}
return processor;
}
NioProcessor(AbstractPollingIoProcessor<S>).add(S) 把IoSession加入到Processor线程中.
public final void add(S session)
{
if (disposed || disposing)
{
throw new IllegalStateException("Already disposed.");
}
//当IoAcceptor接受到新的IoSession中,把IoSession和IoProcessor相关联
// Adds the session to the newSession queue and starts the worker
newSessions.add(session);
startupProcessor();
}
private void startupProcessor()
{
Processor processor = processorRef.get();
if (processor == null)
{
processor = new Processor();
if (processorRef.compareAndSet(null, processor))
{
//触发一个新的ioprocess来执行iosession
executor.execute(new NamePreservingRunnable(processor, threadName)); //Acceptor线程到此把新IoSession与IoProcessor线程相关联。
}
}
// Just stop the select() and start it again, so that the processor
// can be activated immediately.
wakeup();
}
/**
* The main loop. This is the place in charge to poll the Selector, and to
* process the active sessions. It's done in
* - handle the newly created sessions
* -
*/
//内部类Processor线程是处理IO读写操作的主要循环类。在Processor中,不断轮训Select()操作来判断IO操作动作的完成。
private class Processor implements Runnable
{
public void run()
{
assert (processorRef.get() == this);
int nSessions = 0;
lastIdleCheckTime = System.currentTimeMillis();
for (;;)
{
try
{
// This select has a timeout so that we can manage
// idle session when we get out of the select every
// second. (note : this is a hack to avoid creating
// a dedicated thread).
//在run()方法中执行 select()方法
long t0 = System.currentTimeMillis();
int selected = select(SELECT_TIMEOUT);
long t1 = System.currentTimeMillis();
long delta = (t1 - t0);
if ((selected == 0) && !wakeupCalled.get() && (delta < 100))
{
// Last chance : the select() may have been
// interrupted because we have had an closed channel.
if (isBrokenConnection())
{
LOG.warn("Broken connection");
// we can reselect immediately
// set back the flag to false
wakeupCalled.getAndSet(false);
continue;
}
else
{
LOG.warn("Create a new selector. Selected is 0, delta = " + (t1 - t0));
// Ok, we are hit by the nasty epoll
// spinning.
// Basically, there is a race condition
// which causes a closing file descriptor not to be
// considered as available as a selected channel, but
// it stopped the select. The next time we will
// call select(), it will exit immediately for the same
// reason, and do so forever, consuming 100%
// CPU.
// We have to destroy the selector, and
// register all the socket on a new one.
registerNewSelector();
}
// Set back the flag to false
wakeupCalled.getAndSet(false);
// and continue the loop
continue;
}
// Manage newly created session first
nSessions += handleNewSessions();
updateTrafficMask();
// Now, if we have had some incoming or outgoing events,
// deal with them
//当select()函数执行完操作时,有IO操作事件完成。
if (selected > 0)
{
process(); //在这里只要有IO操作完成时,就不断处理IO操作。与JBoss Netty操作类似。
}
// Write the pending requests
long currentTime = System.currentTimeMillis();
flush(currentTime);
// And manage removed sessions
nSessions -= removeSessions();
// Last, not least, send Idle events to the idle sessions
notifyIdleSessions(currentTime);
// Get a chance to exit the infinite loop if there are no
// more sessions on this Processor
if (nSessions == 0) {
processorRef.set(null);
if (newSessions.isEmpty() && isSelectorEmpty()) {
// newSessions.add() precedes startupProcessor
assert (processorRef.get() != this);
break;
}
assert (processorRef.get() != this);
if (!processorRef.compareAndSet(null, this)) {
// startupProcessor won race, so must exit processor
assert (processorRef.get() != this);
break;
}
assert (processorRef.get() == this);
}
// Disconnect all sessions immediately if disposal has been
// requested so that we exit this loop eventually.
if (isDisposing()) {
for (Iterator<S> i = allSessions(); i.hasNext();) {
scheduleRemove(i.next());
}
wakeup();
}
} catch (ClosedSelectorException cse) {
// If the selector has been closed, we can exit the loop
// But first, dump a stack trace
ExceptionMonitor.getInstance().exceptionCaught(cse);
break;
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
ExceptionMonitor.getInstance().exceptionCaught(e1);
}
}
}
try {
synchronized (disposalLock) {
if (disposing) {
doDispose();
}
}
} catch (Exception e) {
ExceptionMonitor.getInstance().exceptionCaught(e);
} finally {
disposalFuture.setValue(true);
}
}
}
/**
* Deal with session ready for the read or write operations, or both.
*/
//用于处理IoSession中对于IO完成的读写操作。
private void process(S session)
{
// Process Reads
//真正执行IO读写操作的地方
if (isReadable(session) && !session.isReadSuspended())
{
//执行IO读取操作
read(session);
}
// Process writes
if (isWritable(session) && !session.isWriteSuspended())
{
// add the session to the queue, if it's not already there
if (session.setScheduledForFlush(true))
{
flushingSessions.add(session);
}
}
}
//在IoProcessor中真正执行IO读取操作的地方
private void read(S session)
{
IoSessionConfig config = session.getConfig();
//socket中可以读取字节数量
int bufferSize = config.getReadBufferSize();
IoBuffer buf = IoBuffer.allocate(bufferSize);
//判断数据包是否分包
final boolean hasFragmentation = session.getTransportMetadata().hasFragmentation();
try {
int readBytes = 0; //可以读取最大数据。
int ret;
try {
if (hasFragmentation) {
while ((ret = read(session, buf)) > 0) {
readBytes += ret;
if (!buf.hasRemaining()) {
break;
}
}
} else {
ret = read(session, buf);
if (ret > 0) {
readBytes = ret;
}
}
} finally {
buf.flip();
}
if (readBytes > 0)
{
//在session相关联的FilterChain中相关联的过滤链
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireMessageReceived(buf); //当线程执行到IO操作读取时,不断读取缓冲区数,并通知Handler来处理数据逻辑。所以,在这里没有处理分包和逻辑处理。需要在Handler中对于分包和逻辑包来处理。
buf = null;
if (hasFragmentation) {
if (readBytes << 1 < config.getReadBufferSize()) {
session.decreaseReadBufferSize();
} else if (readBytes == config.getReadBufferSize()) {
session.increaseReadBufferSize();
}
}
}
if (ret < 0) {
// scheduleRemove(session);
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireInputClosed();
}
} catch (Exception e) {
if (e instanceof IOException) {
if (!(e instanceof PortUnreachableException)
|| !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
|| ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable()) {
scheduleRemove(session);
}
}
IoFilterChain filterChain = session.getFilterChain();
filterChain.fireExceptionCaught(e);
}
}